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); |
2
Time Complexity: O(n log n)
Auxiliary Space: O(n).