Open In App

Check if a path exists in a tree with K vertices present or are at most at a distance D

Last Updated : 29 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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
    # 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>


Output: 

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.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads