poj 1330 Nearest Common Ancestors(LCA模板)

http://poj.org/problem?id=1330

题意:给出两个点,求出这两个点最近的公共祖先。

求LCA的模板题。

大致思路就是访问到某个节点时,先将它自己加入集合中,然后递归访问它的子树,同时把子树加入到集合中来。子树搜索完毕后,判断该节点是否是输入的两个节点之一,若是,并且另外一个也已标记为访问过,那么另外一个节点的祖先便是他们的LCA。

#include<stdio.h>
#include<algorithm>
#include<vector>
#include<string.h>
using namespace std;

const int maxn = 10010;
struct node
{
	int u,v,next;
}edge[maxn];

int p[maxn],cnt;//前向星
int in[maxn];
int vis[maxn];
int pre[maxn];//祖先
int n,x,y;

void add(int u, int v)//加边
{
	edge[cnt] = (struct node){u,v,p[u]};
	p[u] = cnt;
	cnt++;
}

int find(int x)
{
	if(x != pre[x])
		pre[x] = find(pre[x]);
	return pre[x];
}

void LCA(int u)
{
	pre[u] = u;//设立当前节点的集合,先把自己形成一个集合
	
	for(int i = p[u]; i != -1; i = edge[i].next)
	{
		LCA(edge[i].v);//搜索子树
		pre[edge[i].v] = u;//合并子树
	}
	vis[u] = 1;//标记已被访问
	
	//如果当前点是查询中两点中的一点并且另外一点已经访问过,那么另一点的祖先即为公共祖先  
	if(u == x && vis[y])
	{
		printf("%d\n",find(y));
		return;
	}
	if(u == y && vis[x])
	{
		printf("%d\n",find(x));
		return;
	}
}

int main()
{
	int test,u,v;
	scanf("%d",&test);
	while(test--)
	{
		scanf("%d",&n);
		memset(p,-1,sizeof(p));
		memset(in,0,sizeof(in));
		memset(vis,0,sizeof(vis));
		cnt = 0;
		for(int i = 1; i < n; i++)
		{
			scanf("%d %d",&u,&v);
			in[v]++;
			add(u,v);
		}
		scanf("%d %d",&x,&y);
		for(int i = 1; i <= n; i++)
		{
			if(in[i] == 0)
				LCA(i);
		}
	}
	return 0;
}



你可能感兴趣的:(LCA)