Given an undirected tree consisting of n vertices and n-1 edges. The task is to add the minimum number of edges in such a way that the length of the shortest path from vertex 1 to any other vertex is at most 2. The edges should be added in a way that the graph does not contain any loops.
Example:
Input: n = 7, edges = {{1, 2}, {2, 3}, {2, 4}, {4, 5}, {4, 6}, {5, 7}}
Output: 2Input: n = 7, edges = {{1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {1, 7}}
Output: 0
Approach:
The idea is to perform a Depth-First Search (DFS) on an undirected tree to calculate the distance of each vertex from the root. It then identifies vertices whose distance from the root exceeds 2 and removes them along with their neighbors iteratively until the resulting graph satisfies the condition of having a minimum shortest path of at most 2 from vertex 1 to any other vertex. The count of removed vertices and their neighbors represents the minimum number of edges to be added to meet the given criteria.
Step-by-step approach:
- DFS to Calculate Distances:
- Perform a Depth-First Search (DFS) on the tree to calculate the distance of each vertex from the root (vertex 1).
- Store the parent of each vertex and the distance from the root.
- Identify Vertices to Remove:
- Identify vertices whose distance from the root is greater than 2.
- Use a set to store these vertices along with their distances.
- Remove Vertices Iteratively:
- While there are vertices to remove:
- Remove a vertex and its corresponding distance from the set.
- Remove the same vertex and its neighbors from the set.
- Increment the answer count.
- While there are vertices to remove:
- Print the count of removed vertices, which represents the minimum number of edges to add.
Below is the implementation of the above approach:
#include <bits/stdc++.h>
using namespace std;
const int MAX_VERTICES = 200 * 1000 + 11;
int parent[MAX_VERTICES]; // Array to store parent of each
// vertex in the DFS traversal
int distanceFromRoot[MAX_VERTICES]; // Array to store
// distance of each
// vertex from the root
vector<int>
tree[MAX_VERTICES]; // Adjacency list representation of
// the tree
// Depth-first search to compute distances from the root
void computeDistances(int currentVertex,
int parentVertex = -1,
int currentDistance = 0)
{
distanceFromRoot[currentVertex] = currentDistance;
parent[currentVertex] = parentVertex;
for (auto adjacentVertex : tree[currentVertex]) {
if (adjacentVertex != parentVertex) {
computeDistances(adjacentVertex, currentVertex,
currentDistance + 1);
}
}
}
int main()
{
// input
int numberOfVertices = 7;
vector<pair<int, int> > edges
= { { 1, 2 }, { 2, 3 }, { 2, 4 },
{ 4, 5 }, { 4, 6 }, { 5, 7 } };
// Building the tree
for (const auto& edge : edges) {
int vertex1 = edge.first - 1;
int vertex2 = edge.second - 1;
tree[vertex1].push_back(vertex2);
tree[vertex2].push_back(vertex1);
}
// Compute distances from the root (vertex 0)
computeDistances(0);
set<pair<int, int> > verticesToRemove;
// Collect vertices with distances greater than 2
for (int i = 0; i < numberOfVertices; ++i) {
if (distanceFromRoot[i] > 2) {
verticesToRemove.insert(
make_pair(-distanceFromRoot[i], i));
}
}
int additionalEdges = 0;
// Remove vertices and their neighbors until the tree
// satisfies the condition
while (!verticesToRemove.empty()) {
int currentVertex
= verticesToRemove.begin()->second;
currentVertex = parent[currentVertex];
++additionalEdges;
auto it = verticesToRemove.find(
make_pair(-distanceFromRoot[currentVertex],
currentVertex));
if (it != verticesToRemove.end()) {
verticesToRemove.erase(it);
}
for (auto adjacentVertex : tree[currentVertex]) {
auto it = verticesToRemove.find(
make_pair(-distanceFromRoot[adjacentVertex],
adjacentVertex));
if (it != verticesToRemove.end()) {
verticesToRemove.erase(it);
}
}
}
printf("%d\n", additionalEdges);
return 0;
}
import java.util.*;
// Custom Pair class
class Pair<X, Y> {
public final X first;
public final Y second;
public Pair(X first, Y second) {
this.first = first;
this.second = second;
}
}
public class Main {
static final int MAX_VERTICES = 200000 + 11;
// Array to store parent of each vertex in the DFS traversal
static int[] parent = new int[MAX_VERTICES];
// Array to store distance of each vertex from the root
static int[] distanceFromRoot = new int[MAX_VERTICES];
// Adjacency list representation of the tree
static List<Integer>[] tree = new ArrayList[MAX_VERTICES];
// Depth-first search to compute distances from the root
static void computeDistances(int currentVertex,
int parentVertex,
int currentDistance) {
distanceFromRoot[currentVertex] = currentDistance;
parent[currentVertex] = parentVertex;
for (int adjacentVertex : tree[currentVertex]) {
if (adjacentVertex != parentVertex) {
computeDistances(adjacentVertex, currentVertex, currentDistance + 1);
}
}
}
public static void main(String[] args) {
// input
int numberOfVertices = 7;
List<int[]> edges = Arrays.asList(
new int[]{1, 2}, new int[]{2, 3}, new int[]{2, 4},
new int[]{4, 5}, new int[]{4, 6}, new int[]{5, 7}
);
// Initializing the tree
for (int i = 0; i < MAX_VERTICES; i++) {
tree[i] = new ArrayList<>();
}
// Building the tree
for (int[] edge : edges) {
int vertex1 = edge[0] - 1;
int vertex2 = edge[1] - 1;
tree[vertex1].add(vertex2);
tree[vertex2].add(vertex1);
}
// Compute distances from the root (vertex 0)
computeDistances(0, -1, 0);
TreeSet<Pair<Integer, Integer>> verticesToRemove = new TreeSet<>(
Comparator.comparing((Pair<Integer, Integer> p) -> p.first)
.thenComparing(p -> p.second)
);
// Collect vertices with distances greater than 2
for (int i = 0; i < numberOfVertices; ++i) {
if (distanceFromRoot[i] > 2) {
verticesToRemove.add(new Pair<>(-distanceFromRoot[i], i));
}
}
int additionalEdges = 0;
// Remove vertices and their neighbors until the tree satisfies the condition
while (!verticesToRemove.isEmpty()) {
int currentVertex = verticesToRemove.first().second;
currentVertex = parent[currentVertex];
++additionalEdges;
Iterator<Pair<Integer, Integer>> iterator = verticesToRemove.iterator();
while (iterator.hasNext()) {
Pair<Integer, Integer> entry = iterator.next();
if (entry.second == currentVertex) {
iterator.remove();
}
}
for (int adjacentVertex : tree[currentVertex]) {
iterator = verticesToRemove.iterator();
while (iterator.hasNext()) {
Pair<Integer, Integer> entry = iterator.next();
if (entry.second == adjacentVertex) {
iterator.remove();
}
}
}
}
System.out.printf("%d\n", additionalEdges);
}
}
// This code is contributed by akshitaguprzj3
from collections import defaultdict
MAX_VERTICES = 200 * 1000 + 11
# Array to store parent of each
# vertex in the DFS traversal
parent = [0] * MAX_VERTICES
# Array to store
# distance of each
# vertex from the root
distance_from_root = [0] * MAX_VERTICES
tree = defaultdict(list) # Adjacency list representation of
# the tree
# Depth-first search to compute distances from the root
def compute_distances(current_vertex, parent_vertex=-1, current_distance=0):
distance_from_root[current_vertex] = current_distance
parent[current_vertex] = parent_vertex
for adjacent_vertex in tree[current_vertex]:
if adjacent_vertex != parent_vertex:
compute_distances(adjacent_vertex, current_vertex,
current_distance + 1)
def main():
# input
number_of_vertices = 7
edges = [(1, 2), (2, 3), (2, 4), (4, 5), (4, 6), (5, 7)]
# Building the tree
for edge in edges:
vertex1, vertex2 = edge
vertex1 -= 1
vertex2 -= 1
tree[vertex1].append(vertex2)
tree[vertex2].append(vertex1)
# Compute distances from the root (vertex 0)
compute_distances(0)
vertices_to_remove = set()
# Collect vertices with distances greater than 2
for i in range(number_of_vertices):
if distance_from_root[i] > 2:
vertices_to_remove.add((-distance_from_root[i], i))
additional_edges = 0
# Remove vertices and their neighbors until the tree
# satisfies the condition
while vertices_to_remove:
current_vertex = vertices_to_remove.pop()[1]
current_vertex = parent[current_vertex]
additional_edges += 1
if (-distance_from_root[current_vertex], current_vertex) in vertices_to_remove:
vertices_to_remove.remove(
(-distance_from_root[current_vertex], current_vertex))
for adjacent_vertex in tree[current_vertex]:
if (-distance_from_root[adjacent_vertex], adjacent_vertex) in vertices_to_remove:
vertices_to_remove.remove(
(-distance_from_root[adjacent_vertex], adjacent_vertex))
print(additional_edges)
if __name__ == "__main__":
main()
# This code is contributed by ragul21
using System;
using System.Collections.Generic;
using System.Linq;
class Graph
{
const int MAX_VERTICES = 200000 + 11;
// Arrays to store parent and distance information for each vertex
static int[] parent = new int[MAX_VERTICES];
static int[] distanceFromRoot = new int[MAX_VERTICES];
// Dictionary to represent the tree structure
static Dictionary<int, List<int>> tree = new Dictionary<int, List<int>>();
// Recursive function to compute distances from the root vertex
static void ComputeDistances(int currentVertex, int parentVertex = -1, int currentDistance = 0)
{
distanceFromRoot[currentVertex] = currentDistance;
parent[currentVertex] = parentVertex;
// Traverse each adjacent vertex and recursively compute distances
foreach (var adjacentVertex in tree[currentVertex])
{
if (adjacentVertex != parentVertex)
{
ComputeDistances(adjacentVertex, currentVertex, currentDistance + 1);
}
}
}
static void Main()
{
// Number of vertices in the graph
int numberOfVertices = 7;
// List of edges as tuples
List<Tuple<int, int>> edges = new List<Tuple<int, int>>
{
Tuple.Create(1, 2),
Tuple.Create(2, 3),
Tuple.Create(2, 4),
Tuple.Create(4, 5),
Tuple.Create(4, 6),
Tuple.Create(5, 7)
};
// Populate the tree structure based on the edges
foreach (var edge in edges)
{
int vertex1 = edge.Item1 - 1;
int vertex2 = edge.Item2 - 1;
if (!tree.ContainsKey(vertex1))
tree[vertex1] = new List<int>();
if (!tree.ContainsKey(vertex2))
tree[vertex2] = new List<int>();
tree[vertex1].Add(vertex2);
tree[vertex2].Add(vertex1);
}
// Compute distances from the root (vertex 0)
ComputeDistances(0);
// Set to store vertices that need to be removed
HashSet<Tuple<int, int>> verticesToRemove = new HashSet<Tuple<int, int>>();
// Identify vertices with distances greater than 2 and add them to the set
for (int i = 0; i < numberOfVertices; i++)
{
if (distanceFromRoot[i] > 2)
{
verticesToRemove.Add(Tuple.Create(-distanceFromRoot[i], i));
}
}
// Counter for additional edges to be added
int additionalEdges = 0;
// Process vertices to be removed and update additional edges
while (verticesToRemove.Count > 0)
{
var currentVertex = verticesToRemove.First(); // Use First to get the first element
verticesToRemove.Remove(currentVertex);
int vertex = currentVertex.Item2;
vertex = parent[vertex];
additionalEdges++;
// Remove the corresponding vertex from the set
if (verticesToRemove.Contains(Tuple.Create(-distanceFromRoot[vertex], vertex)))
{
verticesToRemove.Remove(Tuple.Create(-distanceFromRoot[vertex], vertex));
}
// Remove adjacent vertices from the set
foreach (var adjacentVertex in tree[vertex])
{
if (verticesToRemove.Contains(Tuple.Create(-distanceFromRoot[adjacentVertex], adjacentVertex)))
{
verticesToRemove.Remove(Tuple.Create(-distanceFromRoot[adjacentVertex], adjacentVertex));
}
}
}
// Print the result (number of additional edges)
Console.WriteLine(additionalEdges);
}
}
const MAX_VERTICES = 200000 + 11;
let parent = new Array(MAX_VERTICES); // Array to store parent of each vertex in the DFS traversal
let distanceFromRoot = new Array(MAX_VERTICES); // Array to store distance of each vertex from the root
let tree = new Array(MAX_VERTICES).fill(null).map(() => []); // Adjacency list representation of the tree
// Depth-first search to compute distances from the root
function computeDistances(currentVertex, parentVertex = -1, currentDistance = 0) {
distanceFromRoot[currentVertex] = currentDistance;
parent[currentVertex] = parentVertex;
for (const adjacentVertex of tree[currentVertex]) {
if (adjacentVertex !== parentVertex) {
computeDistances(adjacentVertex, currentVertex, currentDistance + 1);
}
}
}
// input
const numberOfVertices = 7;
const edges = [[1, 2], [2, 3], [2, 4], [4, 5], [4, 6], [5, 7]];
// Building the tree
for (const edge of edges) {
const vertex1 = edge[0] - 1;
const vertex2 = edge[1] - 1;
tree[vertex1].push(vertex2);
tree[vertex2].push(vertex1);
}
// Compute distances from the root (vertex 0)
computeDistances(0);
let verticesToRemove = new Set();
// Collect vertices with distances greater than 2
for (let i = 0; i < numberOfVertices; ++i) {
if (distanceFromRoot[i] > 2) {
verticesToRemove.add(i);
}
}
let additionalEdges = 0;
// Remove vertices and their neighbors until the tree satisfies the condition
while (verticesToRemove.size > 0) {
let currentVertex = verticesToRemove.values().next().value;
verticesToRemove.delete(currentVertex);
for (const adjacentVertex of tree[currentVertex]) {
verticesToRemove.delete(adjacentVertex);
}
++additionalEdges;
}
console.log(additionalEdges);
Output
2
Time Complexity: O(n log n)
Auxiliary Space: O(n).