HDU1213通暢工程-並查集求解

並查集的經典題目。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;
}
相關文章
相關標籤/搜索