查询树中的祖先-后代关系
给定一棵有 N 个顶点和 N-1 条边的有根树。我们将得到很多对顶点 u 和 v,我们需要判断 u 是否是 v 的祖先。给定的树将植根于索引为 0 的顶点。
例子:
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