倍增法求最近公共祖先(LCA)
2017-07-17 22:15
381 查看
思路分析
首先定义一个f[a][b]数组,注意因为b表示的是a向上跳2^b步所到达的点,所以b不需要开得很大,20就足够了。
然后利用邻接表存图,开一个d[]数组利用搜索遍历这张图来记录深度,然后就可以求LCA了。
求LCA时要注意:如果所求的两个点的深度不同,则先让深度大的那个节点向上跳到与另一节点同一高度,再开始让两个点同时跳同样步数。
代码注释很详细,这里就不再详述。
首先定义一个f[a][b]数组,注意因为b表示的是a向上跳2^b步所到达的点,所以b不需要开得很大,20就足够了。
然后利用邻接表存图,开一个d[]数组利用搜索遍历这张图来记录深度,然后就可以求LCA了。
求LCA时要注意:如果所求的两个点的深度不同,则先让深度大的那个节点向上跳到与另一节点同一高度,再开始让两个点同时跳同样步数。
代码注释很详细,这里就不再详述。
#include<algorithm> #include<iostream> #include<iomanip> #include<cstring> #include<cstdio> #include<cmath> using namespace std; int n,m,s,ans=-1,t,a,b,maxdepth,cnt,gap; int f[10000003][20]; //f[i][j]表示从点i向上跳2^j步所能到达的点 int head[10000003],d[10000003]; struct node { int to; int next; }e[10000003]; void change(int &x,int &y) { int gal=x; x=y; y=gal; } void add(int x,int y)//邻接表 { e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } void dfs(int x) { for(int i=head[x];i;i=e[i].next) { t=e[i].to; if(d[t]) continue;//如果已经记录该点深度则跳过 d[t]=d[x]+1;//当前节点的深度=其父节点的深度+1 f[t][0]=x;//表示t向上走2^0=1步到达其父节点 dfs(t);//继续遍历 } } void doubleinsert() { for(int i=1;i<=maxdepth;i++) { for(int j=1;j<=n;j++) { f[j][i]=f[f[j][i-1]][i-1];//拆分为两部分 } } } void LCA(int x,int y) { if(d[x]<d[y]) change(x,y); gap=d[x]-d[y]; for(int i=0;i<=maxdepth;i++) { if((1<<i)&gap) //转为二进制:gap=2^i1(只要这一位是1)+2^i2+2^i3+... { x=f[x][i];//向上跳2^i步 } } if(x==y)//此时x和y在一棵树的同一侧,取深度最小的 { ans=x; return; } for(int i=maxdepth;i>=0;i--) { if(f[x][i]!=f[y][i]) //因为f[x][i]==f[y][i]时不一定能跳到最近的那个祖先,所以先判断如果不在同一点就跳 { x=f[x][i]; y=f[y][i]; } } //此时x点已经离最近公共祖先仅差1步 ans=f[x][0];//再往上跳一步求得最近公共祖先 return; } int main() { scanf("%d%d%d",&n,&m,&s); maxdepth=log(n)/log(2)+1; //maxdepth用来存储log2(n)+1,可以理解为将可能达到的最长长度用2的次方+1(保险起见)来表示 for(int i=1;i<=n-1;i++) { scanf("%d%d",&a,&b); add(a,b);//无向,所以两个方向都要建边 add(b,a); } d[s]=1;//初始化,记根节点的深度为1 dfs(s);//遍历树,记录每个节点的深度 doubleinsert();//倍增 for(int i=1;i<=m;i++) { ans=-1; scanf("%d%d",&a,&b); LCA(a,b);//查找a和b的最近公共祖先 printf("%d\n",ans); } return 0; }
相关文章推荐
- HDU6115 Factory(最近公共祖先lca,在线倍增,暴力)
- LCA(最近公共祖先)倍增法实现
- HDU - 4547 倍增法求最近公共祖先(LCA)
- 【LCA倍增模板】【poj1330】最近公共祖先
- poj 1986 最近公共祖先 (lca 倍增)
- 求LCA最近公共祖先的在线倍增算法模板_C++
- LCA(最近公共祖先)倍增算法
- POJ1330 Nearest Common Ancestors(在线倍增,离线Tarjan,最近公共祖先LCA)
- 最近公共祖先 LCA 倍增+Tarjan实现
- 用“倍增法”求最近公共祖先(LCA)
- [置顶] 倍增LCA(最近公共祖先)算法详解
- 最近公共祖先LCA倍增算法
- lca(最近公共祖先)倍增模板【pascal】
- 洛谷 P3379 【模板】最近公共祖先(LCA) (在线倍增+离线Tarjan)
- LCA 在线倍增法 求最近公共祖先
- 最近公共祖先(LCA):tarjan与倍增
- 最近公共祖先:LCA及其用倍增实现 +POJ1986
- LCA 在线倍增法 求最近公共祖先
- 【原创】【LCA】求最近公共祖先的三种方法(一)倍增 ※【USACO MAR11银组】聚会地点
- (倍增)最近公共祖先(LCA)模板