LCA---Tarjan算法

Tarjan离线算法求LCA
介绍一种基于Tarjan算法的离线求最低公共祖先(LCA)的方法,该方法适用于有向图和无向图,通过一次深度优先搜索(DFS)完成所有查询的计算。文章提供了两种实现方式,一种使用并查集的Union操作,另一种则不使用并查集。

       本问题中Tarjan算法不需要设置栈和dfn,low标号,而是设置了并查集。

         通过一次dfs遍历即可找出所有节点对的lca。将这样一次读取所有查询,计算一次后返回所有查询lca的算法称为离线算法 

         涉及到在线算法和离线算法这两个概念的算法还有区域最值查询问题(RMQ问题)。

      以下方法均可用于有向图【先查找出根节点root,再DFS】和无向图【root可以任意设置或者是直接遍历所有节点】

      原图和询问可以存储为【链式向前型】和【邻接表】的形式,注意定义形式即可。

【1】使用union函数

 1 void LCA_Tarjan(int u)
 2 {
 3     int now_to;
 4     int i;
 5 
 6     vis[u]=1;   //标记+访问+遍历
 7     ancestor[u]=u;
 8     for(i=Tnode[u].pre;i!=-1;i=Tedge[i].pre)
 9     {
10         now_to=Tedge[i].to_vertex;
11         if(!vis[now_to])
12         {
13             LCA_Tarjan(now_to);
14             Union(u,now_to);
15                 ancestor[Find(now_to)]=u;  //ancestor[Find(u)]=u;  效果一样
16         }
17     }
18     for(i=Qnode[u].pre;i!=-1;i=Qedge[i].pre)
19     {
20         now_to=Qedge[i].to_vertex;
21         if(vis[now_to])
22         {
23             lca[Qedge[i].num]=ancestor[Find(now_to)]; //单独开数组存储
24                  //     Qedge[2*Qedge[i].num-1].ans=Qedge[2*Qedge[i].num].ans=ancestor[Find(now_to)];
25         }
26     }
27 }

【2】不使用union函数

 1 void LCA_Tarjan(int u)
 2 { 
 3     int now_to;   
 4     int i; 
 5     
 6     vis[u]=1;  //标记+访问+遍历
 7     f[u]=u;   //将其父亲(根)指向自己
 8     for(i=Tnode[u].pre;i!=-1;i=Tedge[i].pre) /
 9     {
10         now_to=Tedge[i].to_vertex;
11         if(!vis[now_to])
12         {
13             LCA_Tarjan(now_to);
14             f[now_to]=u;  //存储当前最近公共祖先
15         }
16     }
17 
18     for(i=Qnode[u].pre;i!=-1;i=Qedge[i].pre)  
19     {
20         now_to=Qedge[i].to_vertex;
21         if(vis[now_to])  //如果其子节点及子节点的子树全部访问完才会进入这一步,由vis判断
22         {                //如果已经访问了问题节点,就可以返回结果
23                     lca[Qedge[i].num]=Find(now_to);
24                    //    Qedge[2*Qedge[i].num-1].ans=Qedge[2*Qedge[i].num].ans=Find(now_to);  /*均可*/
25         }
26     }
27 }

 

转载于:https://www.cnblogs.com/wjcx-sqh/p/5929922.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值