Tarjan--LCA算法的个人理解即模板
2014-09-04 16:09
483 查看
tarjan---LCA算法的步骤是(当dfs到节点u时):
实际: 并查集+dfs
具体步骤:
1 在并查集中建立仅有u的集合,设置该集合的祖先为u
1 对u的每个孩子v:
1.1 tarjan之
1.2 合并v到父节点u的集合,确保集合的祖先是u
2 设置u为已遍历
3 处理关于u的查询,若查询(u,v)中的v已遍历过,则LCA(u,v)=v所在的集合的祖先。
举例子:
假设遍历完10的孩子,要处理关于10的请求了
取根节点到当前正在遍历的节点的路径为关键路径,即1-3-8-10
集合的祖先便是关键路径上距离集合最近的点
比如此时:
1,2,5,6为一个集合,祖先为1,集合中点和10的LCA为1
3,7为一个集合,祖先为3,集合中点和10的LCA为3
8,9,11为一个集合,祖先为8,集合中点和10的LCA为8
10,12为一个集合,祖先为10,集合中点和10的LCA为10
你看,集合的祖先便是LCA吧,所以第3步是正确的
道理很简单,LCA(u,v)便是根至u的路径上到节点v最近的点
此段话语来自sre="http://purety.jp/akisame/oi/TJU/"
模板:
实际: 并查集+dfs
具体步骤:
1 在并查集中建立仅有u的集合,设置该集合的祖先为u
1 对u的每个孩子v:
1.1 tarjan之
1.2 合并v到父节点u的集合,确保集合的祖先是u
2 设置u为已遍历
3 处理关于u的查询,若查询(u,v)中的v已遍历过,则LCA(u,v)=v所在的集合的祖先。
举例子:
假设遍历完10的孩子,要处理关于10的请求了
取根节点到当前正在遍历的节点的路径为关键路径,即1-3-8-10
集合的祖先便是关键路径上距离集合最近的点
比如此时:
1,2,5,6为一个集合,祖先为1,集合中点和10的LCA为1
3,7为一个集合,祖先为3,集合中点和10的LCA为3
8,9,11为一个集合,祖先为8,集合中点和10的LCA为8
10,12为一个集合,祖先为10,集合中点和10的LCA为10
你看,集合的祖先便是LCA吧,所以第3步是正确的
道理很简单,LCA(u,v)便是根至u的路径上到节点v最近的点
此段话语来自sre="http://purety.jp/akisame/oi/TJU/"
模板:
#include<iostream> #include<vector> using namespace std; const int MAX=10001; int father[MAX]; int rank[MAX]; int indegree[MAX];//保存每个节点的入度 int visit[MAX]; vector<int> tree[MAX],Qes[MAX]; int ancestor[MAX]; void init(int n) { for(int i=1;i<=n;i++) { rank[i]=1; father[i]=i; indegree[i]=0; visit[i]=0; ancestor[i]=0; tree[i].clear(); Qes[i].clear(); } } int find(int n) { if(father ==n) return n; else father =find(father ); return father ; }//查找函数,并压缩路径 int Union(int x,int y) { int a=find(x); int b=find(y); if(a==b) return 0; //相等的话,x向y合并 else if(rank[a]<=rank[b]) { father[a]=b; rank[b]+=rank[a]; } else { father[b]=a; rank[a]+=rank[b]; } return 1; }//合并函数,如果属于同一分支则返回0,成功合并返回1 void LCA(int u) { ancestor[u]=u; int size = tree[u].size(); for(int i=0;i<size;i++) { LCA(tree[u][i]); Union(u,tree[u][i]); ancestor[find(u)]=u; } visit[u]=1; size = Qes[u].size(); for(int i=0;i<size;i++) { //如果已经访问了问题节点,就可以返回结果了. if(visit[Qes[u][i]]==1) { cout<<ancestor[find(Qes[u][i])]<<endl; return; } } } int main() { int cnt; int n; cin>>cnt; while(cnt--) { cin>>n;; init(n); int s,t; for(int i=1;i<n;i++) { cin>>s>>t; tree[s].push_back(t); indegree[t]++; } //这里可以输入多组询问 cin>>s>>t; //相当于询问两次 Qes[s].push_back(t); Qes[t].push_back(s); for(int i=1;i<=n;i++) { //寻找根节点 if(indegree[i]==0) { LCA(i); break; } } } return 0; }
相关文章推荐
- tarjan离线算法-LCA最近公共祖先算法模板(详细)
- 强连通算法--Tarjan个人理解+详解
- LCA离线tarjan算法模板
- 朱、刘算法:求最小树形图权值个人理解+个人详解【最小树形图模板】
- 朱、刘算法:求最小树形图权值个人理解+个人详解【最小树形图模板】
- 朱、刘算法:求最小树形图权值个人理解+个人详解【最小树形图模板】
- poj 3468..(存线段树个人模板(自敲)pushdown函数还不理解)
- poj 2406 poj 1961 个人对吉大KMP模板的理解 KMP 基础题--找周期串
- hdu 2603 过山车 最大匹配,匈牙利算法模板(易理解)
- tarjan 算法模板(边连通分量)
- floyd 算法的个人理解
- [CF 191C]Fools and Roads[LCA Tarjan算法][LCA 与 RMQ问题的转化][LCA ST算法]
- [CF 191C]Fools and Roads[LCA Tarjan算法][LCA 与 RMQ问题的转化][LCA ST算法]
- (算法)Tarjan离线算法解决LCA问题 (附POJ 1470 Closest Common Ancestors 代码)
- PCA降维算法总结以及matlab实现PCA(个人的一点理解)
- PCA降维算法总结以及matlab实现PCA(个人的一点理解)
- LCA(最近公共祖先)算法的理解。
- 维特比算法一点个人理解
- sicily 2377 Ants Colony 【LCA Tarjan算法】
- floyd 算法的个人理解