並查集的經典題目。node
並查集。經典題目是HDU1232通暢工程。ios
題目描述:測試
某省調查城鎮交通情況,獲得現有城鎮道路統計表,表中列出了每條道路直接連通的城鎮。省政府「暢通工程」的目標是使全省任何兩個城鎮間均可以實現交通(但不必定有直接的道路相連,只要互相間接經過道路可達便可)。問最少還須要建設多少條道路?優化
Output:spa
對每一個測試用例,在1行裏輸出最少還須要建設的道路數目。debug
Sample Input:code
測試輸入包含若干測試用例。每一個測試用例的第1行給出兩個正整數,分別是城鎮數目N ( < 1000 )和道路數目M;隨後的M行對應M條道路,每行給出一對正整數,分別是該條道路直接連通的兩個城鎮的編號。爲簡單起見,城鎮從1到N編號。
注意:兩個城市之間能夠有多條道路相通,也就是說
3 3
1 2
1 2
2 1
這種輸入也是合法的
當N爲0時,輸入結束,該用例不被處理。ci
Sample Output:string
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0it
相互連通的城市組成城市羣。城市羣有一個表明。不斷輸入道路意味着城市之間的互聯,若是這兩個城市原來屬於不一樣城市羣則發生城市羣合併時間。問詢某個城市的城市羣id,依賴於其「父節點」,父節點再從它的父節點詢問,直到Boss節點。
find過程:查找城市羣Boss id的過程。存在路徑優化。
union過程:合併原有的兩個城市羣。利用rank合併,避免最壞狀況線性N級樹結構致使find低效。
一個union的case:
(3) A----------C /|\ /|\ | | |(1) |(2) | | B D /|\ |(4) | E
翻出7年前的AC代碼,發現沒有路徑優化、各類全局變量、
//hdu1213 //find_union_set #include <iostream> #include <stdio.h> using namespace std; int p[1001]; int find(int x) { return p[x]==x?x:p[x]=find(p[x]); } void Union(int a,int b) { p[find(a)]=find(b); } int main() { // freopen("Chris.txt","r",stdin); int n,m; while(scanf("%d",&n)!=EOF) { if(n==0)break; scanf("%d",&m); int i; for(i=0;i<=n;i++) p[i]=i; for(i=0;i<m;i++) { int a,b; scanf("%d%d",&a,&b); if(find(a)!=find(b)) { Union(a,b); n--; } } printf("%d\n",n-1); } return 0; }
考慮去掉全局變量,添加路徑壓縮、利用rank優化union過程、封裝爲結構體、添加註釋,代碼以下:
#include <stdio.h> #include <string.h> #define MAXN 1005 //FSU: Find-Union-Set algorithm node struct typedef struct FSU_Node FSU_Node; struct FSU_Node{ int p; // parent id int rank; // rank is defined as number of childern nodes }; //find node (whose id is x)'s belonging group's root node id // @param x: node id // @param nodes: all the nodes (contain several node groups) int fus_find(int x, FSU_Node* nodes) { if (nodes[x].p == x) return x; nodes[x].p = fus_find(nodes[x].p, nodes); // squeeze the finding path return nodes[x].p; } //merge two node groups // @param a: a node from one node group // @param b: a node from another node group void fus_union(int a, int b, FSU_Node* nodes) { int root_a = fus_find(a, nodes); int root_b = fus_find(b, nodes); if (root_a == root_b) return; // merge node groups according to rank // which avoids the worst case: all nodes in one line (so many level of nodes) if (nodes[root_a].rank > nodes[root_b].rank) { nodes[root_b].p = root_a; } else { if (nodes[root_a].rank == nodes[root_b].rank) { nodes[root_b].rank++; } nodes[root_a].p = root_b; } } #define DEBUG int main() { #ifdef DEBUG freopen("F:/zhangzhuo/debug/OJ/HDU-1232.txt", "r", stdin); #endif FSU_Node nodes[MAXN]; int n, m, i, j, k; while (scanf("%d", &n) && n) { for (i = 0; i <= n; i++) { nodes[i].p = i; nodes[i].rank = 1; } scanf("%d", &m); int cityId1, cityId2; for (i = 0; i < m; i++) { scanf("%d %d", &cityId1, &cityId2); if (fus_find(cityId1, nodes) != fus_find(cityId2, nodes)) { fus_union(cityId1, cityId2, nodes); n--; } } printf("%d\n", n - 1); } return 0; }