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所在集合的祖先。

你可能感兴趣的:(tar)