【算法】並查集模板與練習

並查集

並查集能夠解決「是否暢通問題」,「是否有關係」這一類問題。c++

模板:spa

#include<bits/stdc++.h> 
using namespace std;
int parent[10010]; //祖先,默認-1 
void init(int n){
    for(int i = 0;i<n;i++){
        parent[i] = -1;//祖先的parent存該集合點數的負值 
    }
}
int find(int x){ 
/*尋找x的祖先的編號,若本身就是祖先,返回本身,順便作路徑壓縮 */ 
    int s;
    for(s = x;parent[s]>=0;s = parent[s]);//找到了祖先
    while(x!=s){
        int tmp = parent[x];
        parent[x] = s;
        x = tmp;
    }
    return s;
}
void Union(int a,int b){
    int r1 = find(a),r2 = find(b);
    int total = parent[r1]+parent[r2];
    if(parent[r1] > parent[r2]){
        parent[r1] = r2;
        parent[r2] = total;
    }
    else{
        parent[r2] = r1;
        parent[r1] = total;
    }
}
int main(){
    int n,m,a,b;
    while(scanf("%d%d",&n,&m)){ //n條人 m條關係 
        init(n);
        for(int i = 0;i<n;i++){
            scanf("%d%d",&a,&b);
            if(find(a)!=find(b)){
                //不在同一集合中,則合併
                Union(a,b);
            }
        }   
    }   
    return 0;
}

題目:.net

HDU1272小希的迷宮
上次Gardon的迷宮城堡小希玩了好久(見Problem B),如今她也想設計一個迷宮讓Gardon來走。可是她設計迷宮的思路不同,首先她認爲全部的通道都應該是雙向連通的,就是說若是有一個通道連通了房間A和B,那麼既能夠經過它從房間A走到房間B,也能夠經過它從房間B走到房間A,爲了提升難度,小希但願任意兩個房間有且僅有一條路徑能夠相通(除非走了回頭路)。小希如今把她的設計圖給你,讓你幫忙判斷她的設計圖是否符合她的設計思路。好比下面的例子,前兩個是符合條件的,可是最後一個卻有兩種方法從5到達8。
\(Input:\) 輸入包含多組數據,每組數據是一個以0 0結尾的整數對列表,表示了一條通道鏈接的兩個房間的編號。房間的編號至少爲1,且不超過100000。每兩組數據之間有一個空行。  整個文件以兩個-1結尾。
\(Output:\) 對於輸入的每一組數據,輸出僅包括一行。若是該迷宮符合小希的思路,那麼輸出"Yes",不然輸出"No"。

Sample Input設計

6 8  5 3  5 2  6 4
5 6  0 0

8 1  7 3  6 2  8 9  7 5
7 4  7 8  7 6  0 0

3 8  6 8  6 4
5 3  5 6  5 2  0 0

-1 -1

Sample Outputcode

Yes
Yes
No
/*使用並查集的解法*/
/*使用了一個set記錄頂點*/
#include<bits/stdc++.h>
using namespace std;
int parent[100010];
set<int> ditu;
void init(int n){
    for(int i = 0;i<n;i++){
        parent[i] = -1;
    }
    ditu.clear();
}
int find(int x){
    int s;
    for(s = x;parent[s]>0;s = parent[s]);
    while(s!=x){
        int tmp = parent[x];
        parent[x] = s;
        x = tmp;
    }
    return s;
}
void Union(int a,int b){
    int r1 = find(a),r2 = find(b);
    int tmp = parent[r1]+parent[r2];
    if(parent[r1] > parent[r2]){
        parent[r1] = r2;
        parent[r2] = tmp;
    }else{
        parent[r2] = r1;
        parent[r1] = tmp;
    }
}
int main(){
    int a,b;
    init(1001);
    int flag = 0;
    while(~scanf("%d%d",&a,&b)){
        if(a!=0&&b!=0){
            ditu.insert(a);     
            ditu.insert(b); 
        }
        if(a==-1 && b == -1) break;
        if(a==0&&b==0){
            if(ditu.empty()) {
                printf("Yes\n");
            }
            else if(flag == 1){
                printf("No\n");
            }else{
                int cnt = 0;
                set<int>::iterator it;
                for(it = ditu.begin();it!=ditu.end();it++){
                    if(parent[*it] < 0) cnt++;
                }
                if(cnt==1) printf("Yes\n");
                else printf("No\n");    
            }
            flag = 0;
            init(1001); 
            continue;
        }
        if(find(a) != find(b)){
            Union(a,b);
        }else{
            flag = 1;
        }
    }
}
相關文章
相關標籤/搜索