2 条题解
-
0
数据小就用暴力求就可以了,dfs记录好每个节点的父亲节点。 如果两个节点相等,那么lca就是它们自己。 如果不相等,根据深度来求,深度相等,向上访问父亲节点,直到节点相等。 深度不相等,让大的深度向小的靠拢即可。
int lca(int x,int y) { if(x==y) return x; else if(de[x]==de[y]) return lca(fa[x],fa[y]); else if(de[x]<de[y]) return lca(x,fa[y]); else return lca(fa[x],y); }
数据过大就用倍增求lca,定义father[i][j]为节点i向上跳2^j次方对应的节点是谁, father[i][j]=father[father[i][j-1]][j-1],从i向上2的j次方转移到,从节点father[i][j-1]继续向上2^j-1。dfs时初始化,father[v][0]=u
想找到u,v第一个不同祖先的位置,就要保证u,v在同一深度(才能一起往上移动) 所以这个过程分为三部分,预处理找到每个节点深度,把较深的一点移动到较浅一点的高度,两个一起往上移动直到他们的父亲相同
#include<bits/stdc++.h> using namespace std; int n,de[105],u,v,father[105][8],x,y;//第二维只有8,是因为只有100个节点,2的7次方就已经超过100了 vector<int> e[105]; void dfs(int u,int fa) { for(int i=0;i<e[u].size();i++) { int v=e[u][i]; if(v==fa) continue; de[v]=de[u]+1; father[v][0]=u;//v向上跳一次是u dfs(v,u); } } void st() { for(int j=1;(1<<j)<=n;j++) { for(int i=1;i<=n;i++) { father[i][j]=father[father[i][j-1]][j-1]; } } } int lca(int u,int v) { if(de[u]<de[v]) swap(u,v);//默认u深度大,从u向上走 int h=de[u]-de[v]; for(int i=0;i<8;i++)//这里就是先让两个节点深度相同 { if(h&(1<<i))//二进制位存在1,就需要向上跳。例如h是5,也就是101。 { u=father[u][i]; } } if(u==v)//节点一样直接输出 { return u; } for(int i=7;i>=0;i--)//倒着往回找,找到第一个不相同的节点 第一个不相同的节点的上一个就是最近公共祖先可画图理解 { if(father[u][i]!=father[v][i]) { u=father[u][i]; v=father[v][i]; } } return father[u][0]; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin>>n; cin>>x>>y; for(int i=1;i<n;i++) { cin>>u>>v; e[u].push_back(v); e[v].push_back(u); } de[1]=1; dfs(1,0); st(); cout<<lca(x,y); return 0; }
- 1
信息
- ID
- 1164
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 5
- 标签
- 递交数
- 18
- 已通过
- 16
- 上传者