标签:des style blog http color os strong io
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 17720 | Accepted: 9393 |
Description
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
题目意思:
给出一棵树,然后求最后位置的两个点最近公共祖先。
刚学LCA算法,拿这道题练练手。
本题采用LCA倍增法。
LCA倍增法思想是:若求x,y在树中的最近公共祖先,那么先把x,y置于同一层,然后向上走,当两点走到一起时,此处即为x,y的最近公共祖先。
实现方法:
采用一个数组f[x][i]即为编号为x的结点向上走1<<i步所到的结点的编号,dep[x]为编号为x的结点在树中的深度。
1、dfs遍历整棵树,在遍历过程中由f[x][i]=f[f[x][i-1]][i-1]算出每个结点走1<<i步所到结点编号(该式由来:f[x][i]为编号为x的结点向上走1<<i步所到的结点,那么不就是编号为x的结点向上走两个1<<i-1么);由dep[x]=dep[f[x][0]]+1算出每个结点在树中的深度。
2、把所求两个结点x,y置于同一层,然后向上从能上的最高层向下走即for(i=20;i>=0;i--),若在x,y都向上走1<<i步后两点不重合,那么x,y都等于向上走1<<i步处的结点(我表达能力弱= =,大概意思就是从上到下搜索,由于两点重合处的结点不一定是最近公共祖先,所以向下继续走,若走到1<<i处,低于最近公共祖先,那么两点都移到1<<i处,就这样不断往复,最后达到最近公共祖先)。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 #include <iostream> 6 using namespace std; 7 #define N 10005 8 #define M 20 //M最大为20就够了 毕竟1<<20已经是很高一棵树了 9 10 vector<int>ve[N]; 11 int f[N][M]; 12 int dep[N]; 13 14 void init(){ 15 memset(f,0,sizeof(f)); 16 memset(dep,0,sizeof(dep)); 17 for(int i=0;i<N;i++) ve[i].clear(); 18 } 19 20 void dfs(int root){ 21 int i; 22 dep[root]=dep[f[root][0]]+1; //求深度 23 for(i=1;i<M;i++) f[root][i]=f[f[root][i-1]][i-1]; //求f[x][i] 24 for(i=0;i<ve[root].size();i++) dfs(ve[root][i]); //遍历儿子 25 } 26 27 int LCA(int x,int y){ 28 int i, j, k; 29 if(dep[x]<dep[y]) swap(x,y); //保证x的深度大于y 30 k=dep[x]-dep[y]; 31 for(i=0;i<M;i++){ 32 if(1<<i&k) //进行完这一步后,x与y一定在同一层,想一想为什么 33 x=f[x][i]; 34 } 35 if(x==y) return x; 36 for(i=M-1;i>=0;i--){ //往复搜索最近公共祖先过程 37 if(f[x][i]!=f[y][i]){ 38 x=f[x][i]; 39 y=f[y][i]; 40 } 41 } 42 return f[x][0]; 43 } 44 main() 45 { 46 int t; 47 int n; 48 int i, j, x, y; 49 cin>>t; 50 while(t--){ 51 scanf("%d",&n); 52 init(); 53 int MAX=-1; 54 for(i=0;i<n-1;i++){ 55 scanf("%d %d",&x,&y); 56 ve[x].push_back(y); 57 f[y][0]=x; 58 MAX=max(MAX,x); 59 MAX=max(MAX,y); 60 } 61 int root; 62 for(i=1;i<=MAX;i++){ 63 if(!f[i][0]){ 64 root=i; //找到根结点 65 break; 66 } 67 } 68 scanf("%d %d",&x,&y); 69 dfs(root); //从根结点开始遍历 70 printf("%d\n",LCA(x,y)); 71 } 72 }
标签:des style blog http color os strong io
原文地址:http://www.cnblogs.com/qq1012662902/p/3879681.html