标签:blog http color strong width art
<知识分享>
这是一道考察并查集的路径压缩的题。题意:在悟空的世界,有N个龙珠和N个城市(编号从1到N),神龙最开始把每颗龙珠都放在对应编号的城市。悟空要去收集龙珠,但是这些龙珠有时候是会被转移的。你需要告诉悟空一些有关龙珠的信息才行。现在又T组测试,每组测试都有一个N(龙珠和城市的数量)和Q(操作行为的数量),操作行为有两种:
T A B,将编号为A的龙珠所在城市的所有龙珠转移到编号为B的龙珠所在的城市,两个城市不同
Q A,悟空要知道X(龙珠A所在城市的编号),Y(编号为X的城市里的龙珠数)以及Z(编号为A的龙珠转移的次数)
解题思路:首先根据每个龙珠的编号我们都需要知道3个信息,所在城市的编号,所在城市的龙珠数以及该龙珠被转移过的次数。首先我们分析一下T操作,首先两个城市一定不相同,那么将所有龙珠都移动到另一个城市时,肯定有一个龙珠本来就在那个城市且一次都没有被移动过,这个龙珠就是根节点。那么同理,根节点龙珠肯定从来没被移动过而且不会出现把这个城市的所有龙珠全部移动到空城市这种情况。有了这样的规律,我们可以通过维护根节点所在城市龙珠数来查找这个城市每个龙珠的X和Y。至于Z,路径压缩时我们要把对应节点压缩到根节点之下,对应的Z也要进行同步更新,每次移动时我们只将被移动的城市的根节点的移动次数+1,那么当路径压缩时沿途节点的移动次数之和(当然也包括待压缩节点本身)就是这个节点真正的被移动次数。
接下来是解题代码:
- #include <stdio.h>
- #include <stdlib.h>
- #define N 10001
-
- int bleg[N];
- int tran[N];
- int city[N];
- int bnum[N];
- int t;
- int n, m;
-
- void Init();
-
- int Find(int x);
-
- void Union(int x, int y);
-
- void Q(int x);
-
- int main()
- {
- int tn = 1;
- int i, a, b;
- char ch;
- scanf("%d", &t);
- while (t--)
- {
- scanf("%d %d", &n, &m);
- Init();
- printf("Case %d:\n", tn++);
- for (i=0; i<m; ++i)
- {
- scanf(" %c", &ch);
- if (ch == ‘T‘)
- {
- scanf("%d %d", &a, &b);
- Union(a, b);
- }
- else
- {
- scanf("%d", &a);
- Q(a);
- }
- }
- }
- return 0;
- }
-
- void Init()
- {
- int i;
- for (i=1; i<=n; ++i)
- {
- bleg[i] = city[i] = i;
- tran[i] = 0;
- bnum[i] = 1;
- }
- return;
- }
-
- int Find(int x)
- {
- int y = x;
- int z;
- int ntran = 0;
- while (y != bleg[y])
- {
- ntran += tran[y];
- y = bleg[y];
- }
- while (x != bleg[x])
- {
- z = bleg[x];
- ntran -= tran[x];
- bleg[x] = y;
- tran[x] += ntran;
- x = z;
- }
- return y;
- }
-
- void Union(int x, int y)
- {
- int fx = Find(x);
- int fy = Find(y);
- bleg[fx] = fy;
- ++tran[fx];
- bnum[fy] += bnum[fx];
- return;
- }
-
- void Q(int x)
- {
- int fx = Find(x);
- printf("%d %d %d\n", city[fx], bnum[fx], tran[x]);
- return;
- }
HDOJ-3635-Dragon Balls 解题报告,布布扣,bubuko.com
HDOJ-3635-Dragon Balls 解题报告
标签:blog http color strong width art
原文地址:http://www.cnblogs.com/lxl0928/p/3816400.html