Given a tree with N vertices numbered [0, n – 1], K vertices, and a distance D, the task is to find whether there is a path from the root to some vertex such that each of the K vertices belongs to the path or are at most at a distance D from the path.
Examples:
Input: 0 / \ / \ 1 2 / \ / \ / \ / \ 3 4 5 8 / \ / \ 6 7 / / 9 K = {6, 7, 8, 5}, D = 1 Output: YES Explanation: The path ( 0 - 2 - 5 - 7 ) satisfies the condition. Vertices 5 and 7 are a part of the path. Vertex 6 is the child of vertex 5 and 8 is the child of 2. Input: 0 / \ / \ 1 2 / \ / \ / \ / \ 3 4 5 8 \ / \ \ / \ 10 6 7 / / 9 K = {10, 9, 8, 5}, D = 2 Output: NO Explanation: No such path exists that satisfies the condition.
Approach:
- For every vertex, store their respective parent and depth.
- Select the deepest vertex from the given K vertices
- Keep replacing the K vertices except the root and the deepest vertex by its parent D times
- If the current set of K vertices can form a continuous path, then the answer is Yes or No otherwise.
Below code is the implementation of the above approach:
C++
// C++ implementation of above approach #include <bits/stdc++.h> using namespace std; // Class to represent the Tree class Tree { int T; // Stores the timing of traversals vector< int > parent; // Stores the parent of each vertex vector< int > depth; // Stores the depth of each vertex vector< int > tin; // Stores the time to reach // every vertex vector< int > tout; // Stores the time of leaving // every vertex after DFS calls // from its children vector<vector< int > > edges; // Store the edges public : // Constructor Tree( int n) { T = 0; parent = depth = vector< int >(n); tin = tout = vector< int >(n); edges = vector<vector< int > >(n); } // Adding edges void addEdge( int u, int v) { edges[u].push_back(v); edges[v].push_back(u); } void dfs( int v, int p = -1, int d = 0) { // Store the time to reach vertex v tin[v] = T++; // Store the parent of vertex v parent[v] = p; // Store the depth of vertex v depth[v] = d; // Run DFS for all its children of v for ( auto i : edges[v]) { if (i == p) continue ; dfs(i, v, d + 1); } // Store the leaving time // of vertex v tout[v] = T++; } // Checks and returns whether vertex // v is parent of vertex u or not bool checkTiming( int v, int u) { if (tin[v] <= tin[u] && tout[u] <= tout[v]) return true ; return false ; } // Checks and returns if the path exists void pathExistence(vector< int > k, int d) { int deepest_vertex = k[0]; // Find the deepest vertex among the // given K vertices for ( int i = 0; i < k.size(); i++) { if (depth[k[i]] > depth[deepest_vertex]) deepest_vertex = k[i]; } // Replace each of the K vertices // except for the root and the // deepest vertex for ( int i = 0; i < k.size(); i++) { if (k[i] == deepest_vertex) continue ; int count = d; while (count > 0) { // Stop when root // has been reached if (parent[k[i]] == -1) break ; k[i] = parent[k[i]]; count--; } } bool ans = true ; // Check if each of the K-1 vertices // are a parent of the deepest vertex for ( auto i : k) ans &= checkTiming(i, deepest_vertex); if (ans) cout << "Yes" << endl; else cout << "No" << endl; } }; // Driver Code int main() { Tree t(11); t.addEdge(0, 1); t.addEdge(0, 2); t.addEdge(1, 3); t.addEdge(1, 4); t.addEdge(2, 5); t.addEdge(2, 8); t.addEdge(5, 6); t.addEdge(4, 10); t.addEdge(3, 7); t.addEdge(3, 9); t.dfs(0); vector< int > k = { 2, 6, 8, 5 }; int d = 2; t.pathExistence(k, d); return 0; } |
Java
// Java implementation of above approach import java.util.*; import java.lang.*; class GFG{ static int T; // Stores the timing of traversals static int [] parent; // Stores the parent of each vertex static int [] depth; // Stores the depth of each vertex static int [] tin; // Stores the time to reach // every vertex static int [] tout; // Stores the time of leaving // every vertex after DFS calls // from its children static ArrayList<ArrayList<Integer>> edges; // Adding edges static void addEdge( int u, int v) { edges.get(u).add(v); edges.get(v).add(u); } static void dfs( int v, int p, int d) { // Store the time to reach vertex v tin[v] = T++; // Store the parent of vertex v parent[v] = p; // Store the depth of vertex v depth[v] = d; // Run DFS for all its children of v for (Integer i : edges.get(v)) { if (i == p) continue ; dfs(i, v, d + 1 ); } // Store the leaving time // of vertex v tout[v] = T++; } // Checks and returns whether vertex // v is parent of vertex u or not static boolean checkTiming( int v, int u) { if (tin[v] <= tin[u] && tout[u] <= tout[v]) return true ; return false ; } // Checks and returns if the path exists static void pathExistence( int [] k, int d) { int deepest_vertex = k[ 0 ]; // Find the deepest vertex among the // given K vertices for ( int i = 0 ; i < k.length; i++) { if (depth[k[i]] > depth[deepest_vertex]) deepest_vertex = k[i]; } // Replace each of the K vertices // except for the root and the // deepest vertex for ( int i = 0 ; i < k.length; i++) { if (k[i] == deepest_vertex) continue ; int count = d; while (count > 0 ) { // Stop when root // has been reached if (parent[k[i]] == - 1 ) break ; k[i] = parent[k[i]]; count--; } } boolean ans = true ; // Check if each of the K-1 vertices // are a parent of the deepest vertex for ( int i : k) ans &= checkTiming(i, deepest_vertex); if (ans) System.out.println( "Yes" ); else System.out.println( "No" ); } // Driver code public static void main(String[] args) { int n = 11 ; T = 0 ; parent = new int [n]; depth = new int [n]; tin = new int [n]; tout = new int [n]; edges = new ArrayList<>(); for ( int i = 0 ; i < n; i++) edges.add( new ArrayList<>()); addEdge( 0 , 1 ); addEdge( 0 , 2 ); addEdge( 1 , 3 ); addEdge( 1 , 4 ); addEdge( 2 , 5 ); addEdge( 2 , 8 ); addEdge( 5 , 6 ); addEdge( 4 , 10 ); addEdge( 3 , 7 ); addEdge( 3 , 9 ); dfs( 0 , - 1 , 0 ); int [] k = { 2 , 6 , 8 , 5 }; int d = 2 ; pathExistence(k, d); } } // This code is contributed by offbeat |
Python3
# Python3 implementation of above approach T = 0 n = 11 # Stores the timing of traversals parent = n * [ 0 ] # Stores the parent of each vertex depth = n * [ 0 ] # Stores the depth of each vertex tin = n * [ 0 ] # Stores the time to reach every vertex tout = n * [ 0 ] # Stores the time of leaving # every vertex after DFS calls # from its children edges = [] for i in range (n): edges.append([]) # Adding edges def addEdge(u, v): edges[u].append(v) edges[v].append(u) def dfs(v, p, d): global T # Store the time to reach vertex v T + = 1 tin[v] = T # Store the parent of vertex v parent[v] = p # Store the depth of vertex v depth[v] = d # Run DFS for all its children of v for i in edges[v]: if (i = = p): continue dfs(i, v, d + 1 ) # Store the leaving time # of vertex v T + = 1 tout[v] = T # Checks and returns whether vertex # v is parent of vertex u or not def checkTiming(v, u): if (tin[v] < = tin[u] and tout[u] < = tout[v]): return True return False # Checks and returns if the path exists def pathExistence(k, d): deepest_vertex = k[ 0 ] # Find the deepest vertex among the # given K vertices for i in range ( len (k)): if (depth[k[i]] > depth[deepest_vertex]): deepest_vertex = k[i] # Replace each of the K vertices # except for the root and the # deepest vertex for i in range ( len (k)): if (k[i] = = deepest_vertex): continue count = d while (count > 0 ): # Stop when root # has been reached if (parent[k[i]] = = - 1 ): break k[i] = parent[k[i]] count - = 1 ans = True # Check if each of the K-1 vertices # are a parent of the deepest vertex for i in k: ans & = checkTiming(i, deepest_vertex) if ans: print ( "Yes" ) else : print ( "No" ) addEdge( 0 , 1 ) addEdge( 0 , 2 ) addEdge( 1 , 3 ) addEdge( 1 , 4 ) addEdge( 2 , 5 ) addEdge( 2 , 8 ) addEdge( 5 , 6 ) addEdge( 4 , 10 ) addEdge( 3 , 7 ) addEdge( 3 , 9 ) dfs( 0 , - 1 , 0 ) k = [ 2 , 6 , 8 , 5 ] d = 2 pathExistence(k, d) # This code is contributed by divyeshrabadiya07. |
C#
// C# implementation of above approach using System; using System.Collections.Generic; class GFG { static int T; // Stores the timing of traversals static int [] parent; // Stores the parent of each vertex static int [] depth; // Stores the depth of each vertex static int [] tin; // Stores the time to reach // every vertex static int [] tout; // Stores the time of leaving // every vertex after DFS calls // from its children static List<List< int >> edges; // Adding edges static void addEdge( int u, int v) { edges[u].Add(v); edges[v].Add(u); } static void dfs( int v, int p, int d) { // Store the time to reach vertex v tin[v] = T++; // Store the parent of vertex v parent[v] = p; // Store the depth of vertex v depth[v] = d; // Run DFS for all its children of v foreach ( int i in edges[v]) { if (i == p) continue ; dfs(i, v, d + 1); } // Store the leaving time // of vertex v tout[v] = T++; } // Checks and returns whether vertex // v is parent of vertex u or not static bool checkTiming( int v, int u) { if (tin[v] <= tin[u] && tout[u] <= tout[v]) return true ; return false ; } // Checks and returns if the path exists static void pathExistence( int [] k, int d) { int deepest_vertex = k[0]; // Find the deepest vertex among the // given K vertices for ( int i = 0; i < k.Length; i++) { if (depth[k[i]] > depth[deepest_vertex]) deepest_vertex = k[i]; } // Replace each of the K vertices // except for the root and the // deepest vertex for ( int i = 0; i < k.Length; i++) { if (k[i] == deepest_vertex) continue ; int count = d; while (count > 0) { // Stop when root // has been reached if (parent[k[i]] == -1) break ; k[i] = parent[k[i]]; count--; } } bool ans = true ; // Check if each of the K-1 vertices // are a parent of the deepest vertex foreach ( int i in k) ans &= checkTiming(i, deepest_vertex); if (ans) Console.WriteLine( "Yes" ); else Console.WriteLine( "No" ); } static void Main() { int n = 11; T = 0; parent = new int [n]; depth = new int [n]; tin = new int [n]; tout = new int [n]; edges = new List<List< int >>(); for ( int i = 0; i < n; i++) edges.Add( new List< int >()); addEdge(0, 1); addEdge(0, 2); addEdge(1, 3); addEdge(1, 4); addEdge(2, 5); addEdge(2, 8); addEdge(5, 6); addEdge(4, 10); addEdge(3, 7); addEdge(3, 9); dfs(0, -1, 0); int [] k = { 2, 6, 8, 5 }; int d = 2; pathExistence(k, d); } } // This code is contributed by decode2207. |
Javascript
<script> // Javascript implementation of above approach let T; // Stores the timing of traversals let parent; // Stores the parent of each vertex let depth; // Stores the depth of each vertex let tin; // Stores the time to reach // every vertex let tout; // Stores the time of leaving // every vertex after DFS calls // from its children let edges; // Adding edges function addEdge(u, v) { edges[u].push(v); edges[v].push(u); } function dfs(v, p, d) { // Store the time to reach vertex v tin[v] = T++; // Store the parent of vertex v parent[v] = p; // Store the depth of vertex v depth[v] = d; // Run DFS for all its children of v for (let i = 0; i < edges[v].length; i++) { if (edges[v][i] == p) continue ; dfs(edges[v][i], v, d + 1); } // Store the leaving time // of vertex v tout[v] = T++; } // Checks and returns whether vertex // v is parent of vertex u or not function checkTiming(v, u) { if (tin[v] <= tin[u] && tout[u] <= tout[v]) return true ; return false ; } // Checks and returns if the path exists function pathExistence(k, d) { let deepest_vertex = k[0]; // Find the deepest vertex among the // given K vertices for (let i = 0; i < k.length; i++) { if (depth[k[i]] > depth[deepest_vertex]) deepest_vertex = k[i]; } // Replace each of the K vertices // except for the root and the // deepest vertex for (let i = 0; i < k.length; i++) { if (k[i] == deepest_vertex) continue ; let count = d; while (count > 0) { // Stop when root // has been reached if (parent[k[i]] == -1) break ; k[i] = parent[k[i]]; count--; } } let ans = true ; // Check if each of the K-1 vertices // are a parent of the deepest vertex for (let i = 0; i < k.length; i++) ans &= checkTiming(k[i], deepest_vertex); if (ans) document.write( "Yes" ); else document.write( "No" ); } // Driver code let n = 11; T = 0; parent = new Array(n); depth = new Array(n); tin = new Array(n); tout = new Array(n); edges = []; for (let i = 0; i < n; i++) edges.push([]); addEdge(0, 1); addEdge(0, 2); addEdge(1, 3); addEdge(1, 4); addEdge(2, 5); addEdge(2, 8); addEdge(5, 6); addEdge(4, 10); addEdge(3, 7); addEdge(3, 9); dfs(0, -1, 0); let k = [ 2, 6, 8, 5 ]; let d = 2; pathExistence(k, d); // This code is contributed by mukesh07 </script> |
Yes
Time Complexity: O(N+K*D) where N is the number of vertices in the tree, K is the number of given vertices, and D is the maximum distance that needs to be traversed from each given vertex.
Space Complexity: O(N), which is used to store the various arrays used in the DFS traversal of the tree.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!