Nearest Common Ancestors--POJ 1330
1、题目类型:LCA、并查集、DFS。
2、解题思路:最近公共祖先(Least Common Ancestors):对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。步骤,(1)构造树形结构;(2)用并查集的方法求解LCA,DFS深度搜索树,搜索过程中记录其father节点,直到询问的两个节点找到为止;(3)由于此题只是询问一对节点的最近公共祖先,所以用flag记录其询问是否完成,可以减少运算时间。
3、注意事项:注意LCA函数、Find函数这种递归调用方式。
4、实现方法:
#include<iostream>
#include<vector>
#define MAX 10010
using namespace std;
int n,flag;
int f[MAX],r[MAX],ancestor[MAX];
int indegreen[MAX],vis[MAX];
vector<int> head[MAX],Que[MAX];
void Init()
{
int i,a,b;
cin>>n;
flag=0;
for(i=1;i<=n;i++)
{
head[i].clear();
Que[i].clear();
f[i]=i;
r[i]=1;
ancestor[i]=0;
indegreen[i]=0;
vis[i]=0;
}
for(i=1;i<n;i++)
{
cin>>a>>b;
head[a].push_back(b);
indegreen[b]++;
}
cin>>a>>b;
Que[a].push_back(b);
Que[b].push_back(a);
}
int Find(int u)
{
if(f[u]==u)
return f[u];
else
f[u]=Find(f[u]);
return f[u];
}
void Union(int v,int u)
{
int a,b;
a=Find(v);
b=Find(u);
if(a==b)
return ;
if(r[a]<=r[b])
{
f[a]=b;
r[b]+=r[a];
}
else
{
f[b]=a;
r[a]+=r[b];
}
}
void LCA(int k)
{
int i,size;
size=head[k].size();
ancestor[k]=k;
for(i=0;i<size;i++)
{
if(flag)
break;
LCA(head[k][i]);
Union(k,head[k][i]);
ancestor[Find(k)]=k;
}
vis[k]=1;
size=Que[k].size();
for(i=0;i<size;i++)
{
if(vis[Que[k][i]])
{
flag=1;
cout<<ancestor[Find(Que[k][i])]<<endl;
return ;
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
Init();
for(int i=1;i<=n;i++)
{
if(!indegreen[i])
{
LCA(i);
break;
}
}
}
return 0;
}