Tarjan算法求LCA(最近公共祖先)
来源:互联网 发布:淘宝网商品怎么分期购 编辑:程序博客网 时间:2024/05/26 02:19
LCA的离线算法。复杂度为O(n+q)。
这个算法充分利用了dfs树的结构。
对于每个节点u,关于它的询问(u,v)只有两种。(假设先dfs(u)后dfs(v))
1、v在u的子树内。
此时LCA(u,v) = u.
2、v不在u的子树内。
⑴假设v在u的父亲的另一棵子树内。
此时LCA(u,v) = father[u].
⑵如果不满足条件⑴,则v可能在u的父亲的父亲的另一棵子树内。
而此时LCA(u,v) = father[ father[u] ].
⑶……
观察一下,是不是发现了什么呢?
没错,不论是哪种情况,LCA(u,v)都与u和father[ ]有某种关系。我们能不能抓住这种关系呢?
我们继续观察,一直向上取father[ ],貌似和并查集的FIND操作很像呢。
我们用并查集的角度依次考虑上面的情况试试看。
1、v在u的子树内。
此时dfs(u)还在栈中,没有执行完,此时没有向上取father[ ],说明此时u是根。
2、v不在u的子树内。
⑴假设v在u的父亲的另一棵子树内。
此时的dfs(u)已经执行完并出栈。此时向上取了一次father[ ],说明此时u的父亲是根。
⑵如果不满足条件⑴,则v可能在u的父亲的父亲的另一棵子树内。
同理,此时dfs(u的父亲)也已经执行完并出栈。此时向上取了两次father[ ],说明此时u的父亲的父亲是根。
⑶……
综上,我们只要保证当dfs(u)在栈中的时候,u是根;当dfs(u)不在栈中的时候,father[u]是根就行了。
- #include <stdio.h>
- #include <string.h>
- #include <algorithm>
- using namespace std;
- #define FileIn freopen("in.ads","r",stdin)
- #define FileOut freopen("out.ads","w",stdout)
- #define N 155
- #define M 22555
- struct Vertex
- {
- int head;
- }V[N],Qv[N];
- struct Edge
- {
- int v,next;
- }E[M],Qe[M];
- int top,pre[N];
- bool used[N];
- void Init()
- {
- top = 0;
- memset(V,-1,sizeof(V));
- memset(Qv,-1,sizeof(Qv));
- memset(pre,-1,sizeof(pre));
- memset(used,0,sizeof(used));
- }
- int Root(int x)
- {
- if(pre[x] != -1)
- return pre[x] = Root(pre[x]);
- else
- return x;
- }
- void Union(int a,int b)
- {
- int r1 = Root(a);
- int r2 = Root(b);
- if(r1 != r2)
- pre[r2] = r1;
- }
- void Add_Edge(int u,int v)
- {
- E[top].v = v;
- E[top].next = V[u].head;
- V[u].head = top++;
- }
- void Add_Qedge(int u,int v)
- {
- Qe[top].v = v;
- Qe[top].next = Qv[u].head;
- Qv[u].head = top++;
- }
- void Tarjan(int u)
- {
- used[u] = true;
- for(int i=Qv[u].head;i!=-1;i=Qe[i].next)
- {
- int v = Qe[i].v;
- if(used[v])
- printf("The LCA of (%d,%d) is -> %d\n",u,v,Root(v));
- }
- for(int i=V[u].head;i!=-1;i=E[i].next)
- {
- int v= E[i].v;
- if(used[v])
- continue;
- Tarjan(v);
- Union(u,v);
- }
- }
- int main()
- {
- FileIn;
- int n,m,u,v,Q;
- while(~scanf("%d%d",&n,&m))
- {
- Init();
- while(m--)
- {
- scanf("%d%d",&u,&v);
- Add_Edge(u,v);
- Add_Edge(v,u);
- }
- scanf("%d",&Q);
- while(Q--)
- {
- scanf("%d%d",&u,&v);
- Add_Qedge(u,v);
- Add_Qedge(v,u);
- }
- Tarjan(1);
- }
- return 0;
- }
转自http://blog.csdn.net/dgq8211/article/details/7828478
0 0
- Tarjan算法求LCA(最近公共祖先)
- Tarjan离线算法求最近公共祖先(LCA)
- Tarjan离线算法求最近公共祖先(LCA)
- Tarjan离线算法求最近公共祖先(LCA)
- Tarjan算法求LCA(最近公共祖先)
- [算法] LCA 最近公共祖先 (Tarjan)
- POJ1470 LCA(tarjan离线求最近公共祖先)
- LCA最近公共祖先(tarjan离线算法)
- 最近公共祖先LCA:Tarjan算法
- 最近公共祖先LCA Tarjan算法
- 最近公共祖先LCA Tarjan算法
- 最近公共祖先LCA Tarjan算法
- 最近公共祖先LCA:Tarjan算法
- LCA(最近公共祖先)Tarjan算法
- 最近公共祖先LCA--Tarjan算法
- hdu2586 How far away? Tarjan(离线)算法求最近公共祖先LCA 待补完
- 用于求最近公共祖先(LCA)的 Tarjan算法–以POJ1986为例(转)
- LCA(最近公共祖先)tarjan算法学习笔记
- 手斧Linux – 从LFS到Funtoo (5)
- C#播放wave提示音的类
- 【DP】HDU-3008 Warcraft
- python 网络发送接收数据代码
- 二叉树面试题
- Tarjan算法求LCA(最近公共祖先)
- 手斧Linux – 从LFS到Funtoo (6)
- HTML5学习之路(一)-强大的HTML5
- Spring IoC使用的基本配置
- 手斧Linux – 从LFS到Funtoo (7)
- Android_基础知识_05_推送基础01
- 我之前的博客在DONEWS上
- Java中SimpleDateFormat的简要用法
- java排序和Comparable,Comparator两个接口区别