📜  查询树中的祖先-后代关系

📅  最后修改于: 2022-05-13 01:57:16.984000             🧑  作者: Mango

查询树中的祖先-后代关系

给定一棵有 N 个顶点和 N-1 条边的有根树。我们将得到很多对顶点 u 和 v,我们需要判断 u 是否是 v 的祖先。给定的树将植根于索引为 0 的顶点。

例子:

树ForAncestor1

u = 1    v = 6
we can see from above tree that node 
1 is ancestor of node 6 so the answer 
will be yes.

u = 1    v = 7
we can see from above tree that node 1 
is not an ancestor of node 7 so the
answer will be no.

我们可以使用树的深度优先搜索来解决这个问题。在进行 dfs 时,我们可以观察到访问节点的顺序与其祖先之间的关系。如果我们在dfs中进入和离开该节点时为每个节点分配in-time和out-time,那么我们可以看到对于每对祖先-后代的in-time小于后代的in-time和out-time祖先大于后代,因此使用这种关系我们可以在 O(1) 时间内找到每对节点的结果。

因此,预处理的时间复杂度为 O(N),查询的时间复杂度为 O(1)。

C++
// C++ program to query whether two node has
// ancestor-descendant relationship or not
#include 
using namespace std;
 
// Utility dfs method to assign in and out time
// to each node
void dfs(vector g[], int u, int parent,
         int timeIn[], int timeOut[], int& cnt)
{
    // assign In-time to node u
    timeIn[u] = cnt++;
 
    // call dfs over all neighbors except parent
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v != parent)
            dfs(g, v, u, timeIn, timeOut, cnt);
    }
 
    // assign Out-time to node u
    timeOut[u] = cnt++;
}
 
// method to preprocess all nodes for assigning time
void preProcess(int edges[][2], int V, int timeIn[],
                int timeOut[])
{
    vector g[V];
 
    // construct array of vector data structure
    // for tree
    for (int i = 0; i < V - 1; i++) {
        int u = edges[i][0];
        int v = edges[i][1];
 
        g[u].push_back(v);
        g[v].push_back(u);
    }
 
    int cnt = 0;
 
    // call dfs method from root
    dfs(g, 0, -1, timeIn, timeOut, cnt);
}
 
// method returns "yes" if u is a ancestor
// node of v
string isAncestor(int u, int v, int timeIn[],
                  int timeOut[])
{
    bool b = (timeIn[u] <= timeIn[v] &&
             timeOut[v] <= timeOut[u]);
    return (b ? "yes" : "no");
}
 
// Driver code to test abovea methods
int main()
{
    int edges[][2] = {
        { 0, 1 },
        { 0, 2 },
        { 1, 3 },
        { 1, 4 },
        { 2, 5 },
        { 4, 6 },
        { 5, 7 }
    };
 
    int E = sizeof(edges) / sizeof(edges[0]);
    int V = E + 1;
 
    int timeIn[V], timeOut[V];
    preProcess(edges, V, timeIn, timeOut);
 
    int u = 1;
    int v = 6;
    cout << isAncestor(u, v, timeIn, timeOut) << endl;
 
    u = 1;
    v = 7;
    cout << isAncestor(u, v, timeIn, timeOut) << endl;
 
    return 0;
}


Java
// Java program to query whether two node has
// ancestor-descendant relationship or not
import java.util.Vector;
 
class GFG
{
  static int cnt;
 
  // Utility dfs method to assign in and out time
  // to each node
  static void dfs(Vector []g, int u, int parent,
                  int []timeIn, int []timeOut)
  {
 
    // Assign In-time to node u
    timeIn[u] = cnt++;
 
    // Call dfs over all neighbors except parent
    for(int i = 0; i < g[u].size(); i++)
    {
      int v = g[u].get(i);       
      if (v != parent)
        dfs(g, v, u, timeIn, timeOut);
    }
 
    // Assign Out-time to node u
    timeOut[u] = cnt++;
  }
 
  // Method to preprocess all nodes for assigning time
  static void preProcess(int [][]edges, int V,
                         int []timeIn, int []timeOut)
  {
    @SuppressWarnings("unchecked")
    Vector []g = new Vector[V];
    for (int i = 0; i < g.length; i++)
      g[i] = new Vector();
 
    // Conarray of vector data structure
    // for tree
    for(int i = 0; i < V - 1; i++)
    {
      int u = edges[i][0];
      int v = edges[i][1];
      g[u].add(v);
      g[v].add(u);
    }
    cnt = 0;
 
    // Call dfs method from root
    dfs(g, 0, -1, timeIn, timeOut);
  }
 
  // Method returns "yes" if u is a ancestor
  // node of v
  static String isAncestor(int u, int v, int []timeIn,
                           int []timeOut)
  {
    boolean b = (timeIn[u] <= timeIn[v] &&
                 timeOut[v] <= timeOut[u]);
    return (b ? "yes" : "no");
  }
 
  // Driver code   
  public static void main(String[] args)
  {
    int edges[][] = { { 0, 1 },
                     { 0, 2 },
                     { 1, 3 },
                     { 1, 4 },
                     { 2, 5 },
                     { 4, 6 },
                     { 5, 7 } };   
    int E = edges.length;
    int V = E + 1;  
    int []timeIn = new int[V];
    int []timeOut = new int[V];  
    preProcess(edges, V, timeIn, timeOut);   
    int u = 1;
    int v = 6;
    System.out.println(isAncestor(u, v, timeIn,
                                  timeOut));   
    u = 1;
    v = 7;
    System.out.println(isAncestor(u, v, timeIn,
                                  timeOut));
  }
}
 
// This code is contributed by gauravrajput1


Python3
# Python program to query whether two node has
# ancestor-descendant relationship or not
 
cnt = 0
 
# Utility dfs method to assign in and out time
# to each node
def dfs(g: list, u: int, parent: int, timeIn: list, timeOut: list):
    global cnt
 
    # assign In-time to node u
    timeIn[u] = cnt
    cnt += 1
 
    # call dfs over all neighbors except parent
    for i in range(len(g[u])):
        v = g[u][i]
        if v != parent:
            dfs(g, v, u, timeIn, timeOut)
 
    # assign Out-time to node u
    timeOut[u] = cnt
    cnt += 1
 
# method to preprocess all nodes for assigning time
def preProcess(edges: list, V: int, timeIn: list, timeOut: list):
    global cnt
    g = [[] for i in range(V)]
 
    # construct array of vector data structure
    # for tree
    for i in range(V - 1):
        u = edges[i][0]
        v = edges[i][1]
 
        g[u].append(v)
        g[v].append(u)
 
    cnt = 0
 
    # call dfs method from root
    dfs(g, 0, -1, timeIn, timeOut)
 
# method returns "yes" if u is a ancestor
# node of v
def isAncestor(u: int, v: int, timeIn: list, timeOut: list) -> str:
    b = timeIn[u] <= timeIn[u] and timeOut[v] <= timeOut[u]
    return "yes" if b else "no"
 
# Driver Code
if __name__ == "__main__":
    edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (4, 6), (5, 7)]
    E = len(edges)
    V = E + 1
 
    timeIn = [0] * V
    timeOut = [0] * V
    preProcess(edges, V, timeIn, timeOut)
 
    u = 1
    v = 6
    print(isAncestor(u, v, timeIn, timeOut))
 
    u = 1
    v = 7
    print(isAncestor(u, v, timeIn, timeOut))
 
# This code is contributed by
# sanjeev2552


C#
// C# program to query whether two node has
// ancestor-descendant relationship or not
using System;
using System.Collections;
 
class GFG{
 
// Utility dfs method to assign in and out time
// to each node
static void dfs(ArrayList []g, int u, int parent,
                int []timeIn, int []timeOut,
                ref int cnt)
{
     
    // Assign In-time to node u
    timeIn[u] = cnt++;
  
    // Call dfs over all neighbors except parent
    for(int i = 0; i < g[u].Count; i++)
    {
        int v = (int)g[u][i];
         
        if (v != parent)
            dfs(g, v, u, timeIn, timeOut, ref cnt);
    }
  
    // Assign Out-time to node u
    timeOut[u] = cnt++;
}
  
// Method to preprocess all nodes for assigning time
static void preProcess(int [,]edges, int V,
                       int []timeIn, int []timeOut)
{
    ArrayList []g = new ArrayList[V];
     
    for(int i = 0; i < V; i++)
    {
        g[i] = new ArrayList();
    }
  
    // Construct array of vector data structure
    // for tree
    for(int i = 0; i < V - 1; i++)
    {
        int u = edges[i, 0];
        int v = edges[i, 1];
  
        g[u].Add(v);
        g[v].Add(u);
    }
  
    int cnt = 0;
  
    // Call dfs method from root
    dfs(g, 0, -1, timeIn, timeOut, ref cnt);
}
  
// Method returns "yes" if u is a ancestor
// node of v
static string isAncestor(int u, int v, int []timeIn,
                                       int []timeOut)
{
    bool b = (timeIn[u] <= timeIn[v] &&
             timeOut[v] <= timeOut[u]);
    return (b ? "yes" : "no");
}
     
// Driver code   
static void Main()
{
    int [,]edges = { { 0, 1 },
                     { 0, 2 },
                     { 1, 3 },
                     { 1, 4 },
                     { 2, 5 },
                     { 4, 6 },
                     { 5, 7 } };
     
    int E = edges.GetLength(0);
    int V = E + 1;
     
    int []timeIn = new int[V];
    int []timeOut = new int[V];
     
    preProcess(edges, V, timeIn, timeOut);
     
    int u = 1;
    int v = 6;
    Console.Write(isAncestor(u, v, timeIn,
                             timeOut) + "\n");
     
    u = 1;
    v = 7;
    Console.Write(isAncestor(u, v, timeIn,
                             timeOut) + "\n");
}
}
 
// This code is contributed by rutvik_56


Javascript


输出:

yes
no