您的位置:首页 > 其它

LCA最近公共祖先(tarjan离线算法)

2013-10-06 16:56 375 查看
/**LCA算法:首先用CD ..回退到最近公共祖先,再一次性到达目的地。*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
#define mem(a)  memset(a,0,sizeof(a))
#define maxn 1502
#define M   50002
int indegree[maxn];// 用来查找root
int fa[maxn],vis[maxn],query[maxn][maxn];
vector<int> edge[maxn];
map<string,int>m;
int n;//图中节点的个数,编号1~n
struct Allquery{
int a,b;
}p[M];
void init()
{
m.clear();
mem(indegree);
mem(vis);
mem(query);
for(int i=1;i<maxn;i++)
edge[i].clear();
}
int find_father(int i)
{
if(i==fa[i])
return i;
find_father(fa[i]);//不压缩路径
}
void tarjan(int x)
{
for(int i=1;i<=n;i++)
if(vis[i]&&query[x][i])
{
query[x][i]=query[i][x]=find_father(i);
}
fa[x]=x;
vis[x]=1;
for(int i=0;i<edge[x].size();i++)
{
tarjan(edge[x][i]);
fa[edge[x][i]]=x;
}
}
int getDepth(int i,int f,int cnt)
{
if(i==f)
return cnt;
getDepth(fa[i],f,cnt+1);
}
int main()
{
int T,k,q;
cin>>T;
int i,a,b;
char str1[42],str2[42];
while(T--)
{
init();
scanf("%d%d",&k,&q);
n=0;
for(int i=1;i<k;i++)
{
scanf("%s%s",str1,str2);
if(m[str1]==0)m[str1]=++n;
a=m[str1];
if(m[str2]==0)m[str2]=++n;
b=m[str2];
edge[b].push_back(a);
indegree[a]++;//a是孩子
}
//输入查询次数
for(i=0;i<q;i++)
{
scanf("%s%s",str1,str2);
p[i].a=m[str1];
p[i].b=m[str2];
query[p[i].a][p[i].b]=query[p[i].b][p[i].a]=1;
}
//找到root
for(i=1;i<=n;i++)
if(indegree[i]==0)
{
tarjan(i);break;
}
for(i=0;i<q;i++)
{
int f=query[p[i].a][p[i].b];
int ans=getDepth(p[i].a,f,0);//求出a离f的距离
if(p[i].b!=f) ans++;
printf("%d\n",ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: