POJ 1330 Nearest Common Ancestors (最近公共祖先LCA + 详解博客)

LCA问题的tarjan解法模板

LCA问题 详细

1、二叉搜索树上找两个节点LCA


 1 public int query(Node t, Node u, Node v) {
 2     int left = u.value;
 3     int right = v.value;
 4
 5     //二叉查找树内,如果左结点大于右结点,不对,交换
 6     if (left > right) {
 7         int temp = left;
 8         left = right;
 9         right = temp;
10     }
11
12     while (true) {
13         //如果t小于u、v,往t的右子树中查找
14         if (t.value < left) {
15             t = t.right;
16
17         //如果t大于u、v,往t的左子树中查找
18         } else if (t.value > right) {
19             t = t.left;
20         } else {
21             return t.value;
22         }
23     }
24 }  


2、二叉树上找两个节点

 1 node* getLCA(node* root, node* node1, node* node2)
 2 {
 3     if(root == null)
 4         return null;
 5     if(root== node1 || root==node2)
 6         return root;
 7
 8     node* left = getLCA(root->left, node1, node2);
 9     node* right = getLCA(root->right, node1, node2);
10
11     if(left != null && right != null)   // 两个点在root的左右两边,就是root了
12         return root;
13     else if(left != null)  // 哪边不空返回哪边
14         return left;
15     else if (right != null)
16         return right;
17     else
18         return null;
19 }  

题目链接

朴素法求解: 先对树进行dfs标出每一个节点的深度,对于查找的两个点先判断在不在同一深度,不在 移到统一深度,然后在往上找

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstdio>
 5 #include <vector>
 6 using namespace std;
 7 const int Max = 10005;
 8 int t, n, first, second, root;
 9 vector<int> G[Max];
10 int indegree[Max], depth[Max], father[Max];
11 void inputTree()
12 {
13     for (int i = 0; i <= n; i++)
14     {
15         G[i].clear();
16         father[i] = 0;
17         indegree[i] = 0;
18         depth[i] = 0;
19     }
20     int u, v;
21     for (int i = 1; i < n; i++)
22     {
23         scanf("%d%d", &u, &v);
24         G[u].push_back(v);
25         indegree[v]++;
26         father[v] = u;
27     }
28     scanf("%d%d", &first, &second);
29     for (int i = 1; i <= n; i++)
30     {
31         if (indegree[i] == 0)
32         {
33             root = i;
34             break;
35         }
36     }
37 }
38 void dfs_depth(int u, int dep)
39 {
40     depth[u] = dep;
41     int Size = G[u].size();
42     for (int i = 0; i < Size; i++)
43     {
44         dfs_depth(G[u][i], dep + 1);
45     }
46 }
47 int find_ancestor()
48 {
49     while (depth[first] > depth[second])
50     {
51         first = father[first];
52     }
53     while (depth[first] < depth[second])
54     {
55         second = father[second];
56     }
57     while (first != second)  // 这样直接返回first
58     {
59         first = father[first];
60         second = father[second];
61     }
62     return first;
63 }
64 int main()
65 {
66     scanf("%d", &t);
67     while (t--)
68     {
69         scanf("%d", &n);
70         inputTree();
71         dfs_depth(root, 0);
72         printf("%d\n", find_ancestor());
73     }
74     return 0;
75 }

tarjan + 并查集 解法:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstdio>
 5 #include <vector>
 6 using namespace std;
 7 const int Max = 10005;
 8 int t, n, first, second, root;
 9 vector<int> G[Max], querry[Max];
10 int indegree[Max], father[Max], vis[Max];
11 void inputTree()
12 {
13     for (int i = 0; i <= n; i++)
14     {
15         G[i].clear();
16         querry[i].clear();
17         father[i] = i;
18         indegree[i] = 0;
19         vis[i] = 0;
20     }
21     int u, v;
22     for (int i = 1; i < n; i++)
23     {
24         scanf("%d%d", &u, &v);
25         G[u].push_back(v);
26         indegree[v]++;
27     }
28     scanf("%d%d", &first, &second);
29     querry[first].push_back(second);
30     querry[second].push_back(first);
31     for (int i = 1; i <= n; i++)
32     {
33         if (indegree[i] == 0)
34         {
35             root = i;
36             break;
37         }
38     }
39 }
40 int find_father(int x)
41 {
42     if (x == father[x])
43         return x;
44     return father[x] = find_father(father[x]);
45 }
46 void unionSet(int x, int y)
47 {
48     x = find_father(x);
49     y = find_father(y);
50     if (x != y)
51         father[y] = x;
52 }
53 void tarjan(int x)
54 {
55     int Size = G[x].size();
56     for (int i = 0; i < Size; i++)
57     {
58         int v = G[x][i];
59         tarjan(v);
60         unionSet(x, v);
61     }
62     vis[x] = 1;
63     /*
64     if (x == first && vis[second])
65         printf("%d\n", find_father(second));
66     else if (x == second && vis[first])
67         printf("%d\n", find_father(first));
68     */
69     Size =  querry[x].size();
70     for (int i = 0; i < Size; i++)
71     {
72         if (vis[querry[x][i]])
73         {
74             printf("%d\n", find_father(querry[x][i]));
75             return;
76         }
77     }
78
79 }
80 int main()
81 {
82     scanf("%d", &t);
83     while (t--)
84     {
85         scanf("%d", &n);
86         inputTree();
87         tarjan(root);
88     }
89     return 0;
90 }

时间: 2024-10-19 10:53:14

POJ 1330 Nearest Common Ancestors (最近公共祖先LCA + 详解博客)的相关文章

POJ - 1330 Nearest Common Ancestors 最近公共祖先+链式前向星 模板题

A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  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 n

POJ 1330 Nearest Common Ancestors 最近公共祖先

LCA模板题,用倍增法去写 首先把每一个节点的向上\(2^i (i \in \mathbb N)\)个祖先给枚举出来 再把要求公共祖先的两个节点拉到同一深度 向上不断利用倍增一起跳跃同样层数到他们各自的非公共祖先的祖先节点 最后他们一起到达共同祖先节点的子节点,再同时向上走一位即可 在这个过程中,同时维护cost即可 #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long

POJ 1330 Nearest Common Ancestors 倍增算法的LCA

POJ 1330 Nearest Common Ancestors 题意:最近公共祖先的裸题 思路:LCA和ST我们已经很熟悉了,但是这里的f[i][j]却有相似却又不同的含义.f[i][j]表示i节点的第2j个父亲是多少   这个代码不是我的,转自 邝斌博客 1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-9-5 9:45:17 4 File Name :F

POJ 1330 Nearest Common Ancestors LCA(在线RMQ,离线Tarjan)

链接:http://poj.org/problem?id=1330 题意:只看题目就知道题目是什么意思了,最近公共祖先,求在一棵树上两个节点的最近公共祖先. 思路:求最近公共祖先有两种算法,在线和离线,在线方法是用RMQ求LCA,一句话总结就是在从DFS时,从第一个点到第二个点的最短路径中深度最浅的点就是公共祖先,用RMQ处理,一般问题的最优解决方式的复杂度是O(NlogN)的预处理+N*O(1)的查询.离线方法是Tarjan算法,将所有询问的两个点都记录下来,在DFS过程中不断将每个点自身作为

[POJ 1330] Nearest Common Ancestors (朴素方法)

POJ 1330: Nearest Common Ancestors Time Limit: 1000ms Memory Limit: 32Mb Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  In the figure, each node is labeled with an integer fro

POJ - 1330 Nearest Common Ancestors(基础LCA)

POJ - 1330 Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000KB   64bit IO Format: %lld & %llu Submit Status Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  In t

POJ 1330 Nearest Common Ancestors LCA题解

本题是一个多叉树,然后求两点的最近公共单亲节点. 就是典型的LCA问题.这是一个很多解法的,而且被研究的很透彻的问题. 原始的解法:从根节点往下搜索,若果搜索到两个节点分别在一个节点的两边,那么这个点就是最近公共单亲节点了. Trajan离线算法:首次找到两个节点的时候,如果记录了他们的最低单亲节点,那么答案就是这个最低的单亲节点了. 问题是如何有效记录这个最低单亲节点,并有效根据遍历的情况更新,这就是利用Union Find(并查集)记录已经找到的节点,并及时更新最新访问的节点的当前最低单亲节

POJ 1330 Nearest Common Ancestors(树)

Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17628   Accepted: 9335 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: In the figure, each

poj 1330 Nearest Common Ancestors

题目连接 http://poj.org/problem?id=1330 Nearest Common Ancestors Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  In the figure, each node is labeled with an integer from {1, 2,...,