题意分析:
求两个结点的最近公共祖先。
解题思路:
先找出根结点,然后从根结点开始,运用深搜给每个子节点标记深度和父节点。
那么查找公共祖先时,只需将较矮的那个节点往上提到两个节点变为相同高度,
一起往上搜索即可。复杂度:dep[u] + dep[v]
个人感受:
这种做法还是很好理解撒,不过这种做法求单对是O(n)的复杂度,其它类型得换种算法。
先从基础开始~
具体代码如下:
#include<cstdio> #include<cstring> #include<iostream> #include<queue> using namespace std; const int INF = 0x7f7f7f7f; const int MAXN = 1e4 + 111; vector<int> G[MAXN]; int rt, pa[MAXN], dep[MAXN]; void dfs(int v, int p, int d) { pa[v] = p; dep[v] = d; for (int i = 0; i < G[v].size(); ++i) { if (G[v][i] != p) dfs(G[v][i], v, d + 1); } } void init() { dfs(rt, -1, 0); } int lca(int u, int v) { while (dep[u] > dep[v]) u = pa[u]; while (dep[v] > dep[u]) v = pa[v]; while (u != v) { u = pa[u]; v = pa[v]; } return u; } int main() { int n, t; scanf("%d", &t); while (t --) { scanf("%d", &n); for (int i = 1; i <= n; ++i) G[i].clear(), pa[i] = -1; int up = n - 1, u, v; for (int i = 0; i < up; ++i) { scanf("%d%d", &u, &v); pa[v] = u; G[u].push_back(v); } int who = 1; while (pa[who] != -1) who = pa[who]; rt = who; init(); int a, b; scanf("%d%d", &a, &b); printf("%d\n", lca(a, b)); } return 0; }