LCA算法,正常迭代实现与tarjan离线实现

lca算法是用于在一个树或者一个图中,找出两个节点的公共祖先的算法。

有什么用呢?举一个例子:在一棵树上,当我们随便添加一条边的时候,那么就会在原来的树上形成环。如何把这个环找出来呢?嘿嘿,lca算法便是了!

lca算法是运用需要一个预热的过程,简单的说,就是他需要一棵树或者一个图中节点的每个点的深度和父节点。

呵呵,简单啊,DFS就是了。

接下来根据已知的信息,不断的将两个节点往回迭代,直到找到了同一高度,同一个父节点。这个节点便是他们两点的公共祖先了,而这个过程经过的边加起来,便是我们要找的环!

1、DFS(略)

2、

Int  lca(int u,int v) //lca算法,在某一个图中,找出u,v的公共祖先

{

         if(h[u]>h[v]) // 深度不同,单个节点向上攀爬,到与另一节点同一高度

         {

                   while(h[u]>h[v]) //提示:在这个循环里做文章,就可以解决很多环的问题

                   {

                            u=pre[u];

                   }

         }

         else if(h[v]>h[u])

         {

                   while(h[v]>h[u])

                   {

                            v=pre[v];

                   }

         }

         while(u!=v)  //深度相同了,同时向上攀爬,直到成了同一点

         {

                   u=pre[u];

                   v=pre[v];

         }

return  u; //找到了公共祖先

}

 

 

下面是tarjan离线算法实现LCA

自己看的,不好意思

int find(int x) //并查集
{
	if(x!=pre[x])
	{
		pre[x]=find(pre[x]); //路径压缩
	}
	return pre[x];
}

int lca(int u,int f) //当前节点,父节点
{
	pre[u]=u;  //设立当前节点的集合 
	for(node *p=link[u];p;p=p->next)
	{
		if(p->v==f)
			continue;
		lca(p->v,u);  //搜索子树
		pre[p->v]=u; //合并子树
	}
	v[u]=1; //以u点为集合的点搜索完毕
	if(u==A && v[B]==1)
	{
		printf("%d\n",pre[find(B)]);
	}
	else if(u==B && v[A]==1)
	{
		printf("%d\n",pre[find(A)]);
	}
	return 0;
}

 

Tarjan算法基于深度优先搜索的框架,对于新搜索到的一个结点,首先创建由这个结点构成的集合,再对当前结点的每一个子树进行搜索,每搜索完一棵子树,则可确定子树内的LCA询问都已解决。其他的LCA询问的结果必然在这个子树之外,这时把子树所形成的集合与当前结点的集合合并,并将当前结点设为这个集合的祖先。之后继续搜索下一棵子树,直到当前结点的所有子树搜索完。这时把当前结点也设为已被检查过的,同时可以处理有关当前结点的LCA询问,如果有一个从当前结点到结点v的询问,且v已被检查过,则由于进行的是深度优先搜索,当前结点与v的最近公共祖先一定还没有被检查,而这个最近公共祖先的包涵v的子树一定已经搜索过了,那么这个最近公共祖先一定是v所在集合的祖先。

posted @ 2011-08-02 14:11  Accept  阅读(2110)  评论(0编辑  收藏  举报