您的位置:首页 > 其它

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

2011-08-02 14:11 357 查看
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所在集合的祖先。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: