(算法)Tarjan离线算法解决LCA问题 (附POJ 1470 Closest Common Ancestors 代码)
来源:互联网 发布:天猫数据分析平台 编辑:程序博客网 时间:2024/05/05 07:31
对于最近公共祖先问题,我们先来看这样一个性质,当两个节点(u,v)的最近公共祖先是x时,那么我们可以确定的说,当进行后序遍历的时候,必然先访问完x的所有子树,然后才会返回到x所在的节点。这个性质就是我们使用Tarjan算法解决最近公共祖先问题的核心思想。
同时我们会想这个怎么能够保证是最近的公共祖先呢?我们这样看,因为我们是逐渐向上回溯的,所以我们每次访问完某个节点x的一棵子树,我们就将该子树所有节点放进该节点x所在的集合,并且我们设置这个集合所有元素的祖先是该节点x。那么我们有理由相信, 任何一个不属于已经访问的节点和已经访问的节点的LCA一定是当前这个根节点. 于是我们每次访问完一棵子树, 只需要将子树放进根节点对应的集合即可.
我们简单举例来说明这一点。假设我们刚刚已经完成访问的节点是a,那么我们看与其一同被询问的另外一个点b是否已经被访问过了,若已经被访问过了,那么这个时候最近公共祖先必然是b所在集合对应的祖先c,因为我们对a的访问就是从最近公共祖先c转过来的,并且在从c的子树b转向a的时候,我们已经将b的祖先置为了c,同时这个c也是a的祖先,那么c必然是a、b的最近公共祖先。
对于一棵子树所有节点,祖先都是该子树的根节点,所以我们在回溯的时候,时常要更新整个子树的祖先,为了方便处理,我们使用并查集维护一个集合的祖先。总的时间复杂度是O(n+q)的,因为dfs是O(n)的,然后对于询问的处理大概就是O(q)的。
这就是离线LCA求解算法, 也就是拯救世界的Tarjan. 上面可能说的不是很清楚,但是写起来还是比较好写。下面贴上我在POJ 1470上过的题的代码,简单的LCA问题的求解。
/*author UESTC_Nowitzki */#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <vector>using namespace std;const int MAX=1000;int indegree[MAX];int set[MAX];int vis[MAX];int frequency[MAX];vector<int> adj[MAX];vector<int> que[MAX];void init(int n){ memset(frequency,0,sizeof(frequency)); memset(vis,0,sizeof(vis)); memset(indegree,0,sizeof(indegree)); for(int i=1;i<=n;i++) { adj[i].clear(); que[i].clear(); set[i]=i; }}int find(int k){ int r=k; while(set[r]!=r) r=set[r]; int i=k,j; while(set[i]!=r) { j=set[i]; set[i]=r; i=j; } return r;}void dfs(int i){ int len=adj[i].size(); for(int j=0;j<len;j++) { int son=adj[i][j]; dfs(son); set[son]=i; } vis[i]=1; len=que[i].size(); for(int j=0;j<len;j++) { int son=que[i][j]; if(vis[son]) { int ans = find(son); frequency[ans]++; } }}int main(){ int n,i,t,a,b; while(scanf("%d",&n)!=EOF) { init(n); for(i=0;i<n;i++) { scanf("%d:(%d)",&a,&t); while(t--) { scanf("%d",&b); indegree[b]++; adj[a].push_back(b); } } scanf("%d",&t); while(t--) { while(getchar()!='('); scanf("%d%d",&a,&b); que[a].push_back(b); que[b].push_back(a); } while(getchar()!=')'); for(i=1;i<=n;i++) { if(indegree[i]==0) { // printf("root=%d\n",i); dfs(i); break; } } for(i=1;i<=n;i++) { if(frequency[i]>0) printf("%d:%d\n",i,frequency[i]); } } return 0;}
- (算法)Tarjan离线算法解决LCA问题 (附POJ 1470 Closest Common Ancestors 代码)
- (算法)Tarjan离线算法解决LCA问题 (附POJ 1470 Closest Common Ancestors 代码)
- poj 1470 Closest Common Ancestors(离线Tarjan算法)
- poj 1470 Closest Common Ancestors(tarjan离线求lca)
- poj 1470 Closest Common Ancestors (离线LCA Tarjan)
- POJ 1470 Closest Common Ancestors(离线tarjan-LCA)
- POJ 1470Closest Common Ancestors tarjan算法求LCA
- POJ 1470 Closest Common Ancestors LCA Tarjan算法
- POJ 1470 Closest Common Ancestors LCA离线Tarjin算法
- poj1470 Closest Common Ancestors Lca离线算法Tarjan
- poj 1470 Closest Common Ancestors(简单的LCA算法)
- poj 1470 Closest Common Ancestors 【Tarjan 离线 LCA】
- POJ1470/ZOJ1141 Closest Common Ancestors(LCA离线算法)
- [POJ]1330 Nearest Common Ancestors (LCA,DFS+ST在线算法 || 倍增算法 || Tarjan离线算法)
- POJ 1470 Closest Common Ancestors (离线LCA,4级)
- POJ 1470 Closest Common Ancestors【LCA Tarjan】
- poj 1330 Nearest Common Ancestors (LCA) tarjan离线算法
- POJ 1330 Nearest Common Ancestors 【LCA·Tarjan离线算法】
- A+B for Input-Output Practice (VII)
- Windows下搭建object-c
- SST39VF1601 简介(转)
- 学会奖章问题
- 第二章 掌握JSP语法
- (算法)Tarjan离线算法解决LCA问题 (附POJ 1470 Closest Common Ancestors 代码)
- oracle安装后的问题:共享库Libsqlplus.so 无法访问
- 今天是什么
- 错误“ORA-12520: TNS: 监听程序无法找到需要的服务器类型的可用句柄”解决方法
- Combbox控件的下拉长度
- 一位老程序员十年的职场感悟
- 记事本教程
- A+B for Input-Output Practice (VIII)
- 使用Axis开发一个传递PoJo类的例子