任意门:http://poj.org/problem?id=1330
Nearest Common Ancestors
| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 34942 | Accepted: 17695 |
Description
In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is.
For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest common ancestor of y and z is y.
Write a program that finds the nearest common ancestor of two distinct nodes in a tree.
Input
Output
Sample Input
2 16 1 14 8 5 10 16 5 9 4 6 8 4 4 10 1 13 6 15 10 11 6 7 10 2 16 3 8 1 16 12 16 7 5 2 3 3 4 3 1 1 5 3 5
Sample Output
4 3
题意概括:
给一棵有N个节点,N-1条边的树 和 一对结点,求这对结点的最近公共祖先。
解题思路:
找根结点用一个标记数组
找公共祖先用简单粗暴的 Tarjan。
AC code:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #define INF 0x3f3f3f3f 7 #define LL long long 8 using namespace std; 9 const int MAXN = 1e4+5; 10 struct Edge{int v, next;}edge[MAXN<<1]; 11 int head[MAXN], cnt; 12 int fa[MAXN]; 13 bool in[MAXN]; 14 bool vis[MAXN]; 15 int N, M, S, ans, a, b; 16 17 inline void init() 18 { 19 memset(head, -1, sizeof(head)); 20 memset(vis, false, sizeof(vis)); 21 memset(in, false, sizeof(in)); 22 cnt = 0; 23 } 24 25 inline void AddEdge(int from, int to) 26 { 27 edge[cnt].v = to; 28 edge[cnt].next = head[from]; 29 head[from] = cnt++; 30 } 31 32 int findset(int x) 33 { 34 int root = x; 35 while(fa[root] != root) root = fa[root]; 36 37 int tmp; 38 while(fa[x] != root){ 39 tmp = fa[x]; 40 fa[x] = root; 41 x = tmp; 42 } 43 return root; 44 } 45 46 void Tarjan(int s) 47 { 48 fa[s] = s; 49 for(int i = head[s]; i != -1; i = edge[i].next){ 50 int Eiv = edge[i].v; 51 Tarjan(Eiv); 52 fa[findset(Eiv)] = s; 53 } 54 vis[s] = true; 55 if(s == a){ 56 if(vis[a] && vis[b]) ans = findset(b); 57 } 58 else if(s == b){ 59 if(vis[a] && vis[b]) ans = findset(a); 60 } 61 } 62 63 int main() 64 { 65 int T_case, u, v; 66 scanf("%d", &T_case); 67 while(T_case--) 68 { 69 init(); 70 scanf("%d", &N); 71 M = N-1; 72 for(int i = 1; i <= M; i++){ 73 scanf("%d %d", &u, &v); 74 AddEdge(u, v); 75 in[v] = true; 76 //AddEdge(v, u); 77 } 78 scanf("%d %d", &a, &b); 79 int root = 0; 80 for(int i = 1; i <= N; i++){ 81 if(!in[i]){root = i;break;} 82 } 83 Tarjan(root); 84 printf("%d\n", ans); 85 } 86 return 0; 87 }
1万+



被折叠的 条评论
为什么被折叠?



