题目描述:
http://acm.hdu.edu.cn/showproblem.php?pid=3635
中文大意:
日本总共有 n 颗龙珠,被神龙放置在了 n 个城市中。
T A B :将龙珠 A 所在城市中的所有龙珠运送到龙珠 B 的所在城市。假定这两个城市是不同的。
Q A :输出龙珠 X 所在的城市,该市中龙珠的个数以及龙珠 X 的运输次数。
思路:
一个城市就是一个集合,龙珠就是集合中的节点。
本题的难点在于,如何更新每个龙珠的移动次数。
在合并操作中,times[x]++; 只是更新了原根节点的移动次数。而非根节点的移动次数并未更新。
非根节点的移动次数 = 当前节点的移动次数 + 原根节点的移动次数 + ...
这个过程,需要利用迭代操作来实现,请结合下面例子自行体会:
4
T 1 2
T 2 3
T 3 4
Q 1
代码:
#include<iostream>
using namespace std;
int n,q;
int city[10001];//各龙珠所在城市
int times[10001];//各龙珠的移动次数
int cnt[10001];//各城市的龙珠个数
void init(){
for(int i=1;i<=n;i++){
city[i] = i;
times[i] = 0;
cnt[i] = 1;
}
}
//寻找龙珠 x 的所在城市
int find(int x){
if(city[x] == x){
return x;
}
int root = find(city[x]);
//当前龙珠的移动次数 = 当前龙珠移动次数 + 根节点龙珠移动次数
times[x] += times[city[x]];
city[x] = root;
return root;
}
//合并
void union_set(int x, int y){
x = find(x);
y = find(y);
city[x] = y;
times[x]++;
cnt[y] += cnt[x];
}
int main(){
int t;
scanf("%d", &t);
for(int k=1;k<=t;k++){
scanf("%d %d", &n, &q);
init();
printf("Case %d:
",k);
char c;
int x,y;
for(int i=0;i<q;i++){
getchar();
scanf("%c", &c);
if(c == 'T'){
scanf("%d %d", &x, &y);
union_set(x, y);
}
else if(c == 'Q'){
scanf("%d", &x);
int root = find(x);
printf("%d %d %d
", root, cnt[root], times[x]);
}
}
}
}