博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【lca】lca的tarjan写法 poj1330
阅读量:6853 次
发布时间:2019-06-26

本文共 5869 字,大约阅读时间需要 19 分钟。

今天看了一下午的lca的tarjan写法,发现果真还是不能全部理解,不过还是有大部分能够理解,就将自己的思路写在这里备忘吧。。

tarjan算法是基于并查集与dfs的一种离线算法

tarjan算法的步骤是(当dfs到节点u时):

1 在并查集中建立仅有u的集合,设置该集合的祖先为u,就是普通的并查集,fa[i] = i;
1 对u的每个孩子v:
   1.1 tarjan之
   1.2 合并v到父节点u的集合,确保集合的祖先是u
2 设置u为已遍历
3 处理关于u的查询,若查询(u,v)中的v已遍历过,则LCA(u,v)=v所在的集合的祖先

 

 

图上已经讲解的很详细了,这里是并查集的一个应用。。

不过光看思想并不能解决问题,于是我找了一道lca的果题,poj1330

题目链接:

Time Limit: 1000MS   Memory Limit: 10000KB   64bit IO Format: %I64d & %I64u

 

 

Description

A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: 
In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is. 
For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest common ancestor of y and z is y. 
Write a program that finds the nearest common ancestor of two distinct nodes in a tree. 

Input

The input consists of T test cases. The number of test cases (T) is given in the first line of the input file. Each test case starts with a line containing an integer N , the number of nodes in a tree, 2<=N<=10,000. The nodes are labeled with integers 1, 2,..., N. Each of the next N -1 lines contains a pair of integers that represent an edge --the first integer is the parent node of the second integer. Note that a tree with N nodes has exactly N - 1 edges. The last line of each test case contains two distinct integers whose nearest common ancestor is to be computed.

Output

Print exactly one line for each test case. The line should contain the integer that is the nearest common ancestor.

Sample Input

2161 148 510 165 94 68 44 101 136 1510 116 710 216 38 116 1216 752 33 43 11 53 5

Sample Output

43
 

 

其实这道题用RMQ,倍增也可以做,不过今天看的tarjan,就用tarjan做吧,具体看代码注释

【代码】:

先贴一个标程:

1 //O(n+Q)  2   3 #include 
4 #include
5 #include
6 #include
7 8 using namespace std; 9 10 #define MAXN 10001 11 12 int n,fa[MAXN]; 13 int rank[MAXN]; 14 int indegree[MAXN]; 15 int vis[MAXN]; 16 vector
hash[MAXN],Qes[MAXN]; 17 int ances[MAXN];//祖先 18 19 20 void init(int n) 21 { 22 for(int i=0;i<=n;i++) 23 { 24 fa[i]=i; 25 rank[i]=0; 26 indegree[i]=0; 27 vis[i]=0; 28 ances[i]=0; 29 hash[i].clear(); 30 Qes[i].clear(); 31 } 32 } 33 34 int find(int x) 35 { 36 if(x != fa[x]) 37 fa[x]=find(fa[x]); 38 return fa[x]; 39 } 40 41 void unio(int x,int y) 42 { 43 int fx=find(x),fy=find(y); 44 if(fx==fy) return ; 45 if(rank[fy]
View Code

第二个自己写的,应该是对的:

1 #include
2 #include
3 #include
4 #include
5 #define mem(a,x) memset(a, x , sizeof(a)) 6 using namespace std; 7 8 struct edge{ 9 int v,next;10 }e[10000 + 5];11 int ind[10000 + 5];//记录每个点的入度12 int fa[10000 + 5];//并查集用13 int head[10000 + 5], k = 1;14 bool vis[10000 + 5];//判断是否遍历过15 int rnk[10000 + 5];//就是这个不知道什么用,觉得像是并查集压缩路径的优化16 int anc[10000 + 5];//每个点的祖先17 vector
que[10000 + 5];//与x有关的询问放在q[x]中18 int T;19 int root;20 int n;21 22 void init()//初始化23 {24 mem(vis,0);25 mem(head,0);26 mem(fa,0);27 mem(ind,0);28 mem(rnk,0);29 mem(e,0);30 k = 1;31 for(int i = 1; i <= n; i++)32 fa[i] = i,anc[i] = 0,que[i].clear();33 } 34 void adde(int u, int v)//加边,其实觉得用vector数组更好用35 {36 e[k].v = v;37 e[k].next = head[u];38 head[u] = k++;39 }40 int find(int x)//并查集,不解释41 {42 return fa[x] == x ? x : fa[x] = find(fa[x]);43 } 44 void Union(int x, int y)//合并45 {46 int fx = find(x),fy = find(y);47 if(fx == fy)return ;48 if(rnk[fx] > rnk[fy]) fa[fy] = fx;49 else fa[fx] = fy, rnk[fy] += rnk[fx] == rnk[fy];50 }51 52 void tarjan(int u)53 {54 anc[u] = u;//u是u集合的祖先55 for(int i = head[u]; i ; i = e[i].next)//遍历边56 {57 int v = e[i].v;58 if(!vis[v])59 {60 tarjan(v);61 Union(u,v);62 anc[find(u)] = u;//保证u的子树的祖先是u63 }64 }65 vis[u] = 1;66 for(int i = 0; i < que[u].size(); i++)//处理查询67 if(vis[que[u][i]]){68 printf("%d\n",anc[find(que[u][i])]);69 return;70 }71 }72 int main()73 {74 scanf("%d", &T);75 while(T--)76 {77 init();78 scanf("%d", &n);79 for(int i = 1; i < n; i++)80 {81 int u, v;82 scanf("%d%d", &u, &v);83 adde(u,v);84 ind[v]++;85 }86 for(int i = 1; i <= n; i++)87 if(!ind[i]){88 root = i;89 break;90 }91 int a,b;92 scanf("%d%d", &a, &b);93 que[a].push_back(b);que[b].push_back(a);94 tarjan(root);95 }96 return 0;97 }
View Code

暂时就这些了,到时再来慢慢完善吧。

转载于:https://www.cnblogs.com/kiritoghy/p/4689048.html

你可能感兴趣的文章
linux下通过串口登陆交换机
查看>>
微信公众平台群发规则说明
查看>>
LINUX下直接使用ISO文件
查看>>
第四章 apache的工作模式
查看>>
mysql备份和恢复总结
查看>>
软件明明已经删除 控制面板里还有名称
查看>>
深入浅出的SQL server 查询优化
查看>>
Hyper-V vNext新的虚拟机配置文件、配置版本
查看>>
通俗易懂,各常用线程池的执行 流程图
查看>>
CentOS 6.4 安装python2.7/mysqldb/ipython
查看>>
hive0.11 hiveserver custom认证bug
查看>>
Windows Phone SDK 8.0 新特性-Speech
查看>>
VS~单步调试DLL
查看>>
MyEclipse环境下Hibernate入门实例
查看>>
VC+CSocket文件传送示例
查看>>
职业生涯中的选择时机非常重要,各种条件还没成熟时的时候,因为诱惑而贸然行事,只会得到适得其反的结果...
查看>>
[WebDevelopment]搜索引擎优化(SEO)工具包
查看>>
Symbian OS开发入门(二) :VS2003环境下Symbian工程的导入与建立
查看>>
RequiredFieldValidator 根据group组来触发验证
查看>>
[AR]ImageTarget(图像识别)
查看>>