標籤: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); //並查集合并,也就是T操作
-
- 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) //並查集合并,也就是T操作
- {
- int fx = Find(x);
- int fy = Find(y);
- bleg[fx] = fy;
- ++tran[fx]; //被移動的根節點的被移動次數加1
- 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;
- }