以前了解的Tarjin算法是用来求连通分量,在这里是用来求最近公共祖先
并查集用过,很有意思的工具。Kraskal算法是并查集最经典的应用。首先初始化集合,每个元素为单个集合。集合,我们需要选出一个代表,这个代表的性质是set[u] = u。一开始一个集合只有一个元素,所以该集合的代表也就是该元素。当两个集合需要合并时,例如:set[a] = a, set[b] = b。要是把a当作合并后集合的代表,那就让set[b] = a。这样,在find函数中,当发现set[u] != u时,意思就是,u这个元素,是和set[u]这个元素属于同一集合,然后就递归查找,直到set[v] = v,然后回退,更新set[u]。这个步骤叫做“路径压缩”。例如,set[a] = b; set[b]=c; set[c]=d;...., set[y] = z, set[z]=z,当开始find(a)后,会逐步深入到set[z]=z停止,然后回退,令set[y] = z, set[x] = z, set[w] = z, ... set[a] = z,这样,下次再find(a)时,就能很快找到set[z]=z结束,路径是不是变短了呢。
“离线”的意思是,需要预先知道所有的提问。那“在线”的意思就是不需要提前知道问题,你随便问,即刻回答。
先看一下这个参考资料:http://blog.csdn.net/ljsspace/article/details/66910300
这里去掉了参考资料中的ancestor数组。直接用子树的根节点来做集合的代表。从一个节点,走到另一个节点,必然要经过而且最先经过这两个节点的最近公共祖先。所以当发现一个节点A访问了时,马上查询另一个另一个节点B,如果该节点已访问,那B所在集合的代表,就是A和B的最近公共祖先。
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define M 50
#define C 50
#define Q 50
typedef struct _Node{
int data;
int chs;
struct _Node* ch[C];
}Node, *pNode;
typedef struct _Query{
int s, e;
int anc;
}Query, *pQuery;
Query que[Q];
int n, q;
int set[M];
int mk[M];
pNode root;
void init(){
int i;
for(i=0; i<n; i++)
set[i] = i;
}
int find(int u){
if(u!=set[u])
set[u] = find(set[u]);
return set[u];
}
void combine(int u, int v){
set[v] = u;
}
void create(pNode* r){
int i;
int v, c;
scanf("%d %d", &v, &c);
*r = (pNode)malloc(sizeof(Node));
(*r)->data = v;
(*r)->chs = c;
for(i=0; i<c; i++){
create(&((*r)->ch[i]));
}
}
void show(pNode r){
int i;
printf("%d ", r->data);
for(i=0; i<r->chs; i++)
show(r->ch[i]);
}
void LCA(pNode r){
int i;
int t;
for(i=0; i<r->chs; i++){
LCA(r->ch[i]);
combine(r->data, r->ch[i]->data);
}
mk[r->data] = 1;
for(i=0; i<q; i++){
t = -1;
if(r->data==que[i].s && mk[que[i].e])
t = que[i].e;
else if(r->data==que[i].e && mk[que[i].s])
t = que[i].s;
if(t!=-1)
que[i].anc = find(t);
}
}
void main(){
int i;
freopen("in.txt", "r", stdin);
while(scanf("%d %d", &n, &q)!=EOF){
init();
root = 0;
create(&root);
for(i=0; i<q; i++){
scanf("%d %d", &(que[i].s), &(que[i].e));
}
memset(mk, 0, sizeof(mk));
LCA(root);
for(i=0; i<q; i++)
printf("LCA of %d and %d is: %d\n", que[i].s, que[i].e, que[i].anc);
}
}
数据:
20 19
0 2
1 3
3 0
4 2
8 2
12 0
13 0
9 2
14 0
15 0
5 2
10 2
16 0
17 0
11 2
18 0
19 0
2 2
6 0
7 0
8 5
12 14
14 6
6 7
10 9
3 10
14 15
15 8
11 10
13 12
5 4
18 13
4 17
16 19
9 19
10 19
7 17
17 16
18 19