1. 程式人生 > >杭電 hdu 1272 小希的迷宮【並查集】

杭電 hdu 1272 小希的迷宮【並查集】

                  小希的迷宮

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 38688    Accepted Submission(s): 11861


Problem Description 上次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 Output Yes Yes No

這個題目還是有點坑的。首先,我們會思維定式的考慮這個問題,覺得題目保證只有一個集合。那麼我們就會無限WA,一直卡到死~。

思路:

1.每輸入一組資料,都要對其進行連線(merge),如果兩個點find(a)==find(b),那麼說明他們已經是一個集合的了,如果再連線a,b兩個點,就會構成迴路,這裡也就是要輸出no.

void merge(int a,int b)
{
    int A,B;
    A=find(a);
    B=find(b);
    if(A!=B)
    {
        f[B]=A;
    }
    else
    {
        ok=0;//這裡ok==0表示存在迴路~
    }
}

2.並查集判斷是否存在迴路已經通過上述過程判斷完成了,但是我們要保證只有一個集合,題目中沒有保證,所以我們這裡首先要對出現過的點進行標記,然後從1到100000這些個點都進行判斷,如果標記過(表示這個點出現過)並且f[i]==i的話,那麼就說明i現在是個祖宗,表示有一個集合了,這裡如果集合大於1,那就說明要輸出NO了~

            int cont=0;
            for(int i=0;i<=100005;i++)
            {
                if(vis[i]&&f[i]==i)
                cont++;
            }
            if(cont==1)
            {
                printf("Yes\n");
            }
            else
            {
                printf("No\n");
            }

這裡思路清晰了之後呢,我們就可以上完整的AC程式碼了:

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
int ok;
int f[100005];
int vis[100005];
int find(int a)
{
    int r=a;
    while(f[r]!=r)
    r=f[r];
    int i=a;
    int j;
    while(i!=r)
    {
        j=f[i];
        f[i]=r;
        i=j;
    }
    return r;
}
void merge(int a,int b)
{
    int A,B;
    A=find(a);
    B=find(b);
    if(A!=B)
    {
        f[B]=A;
    }
    else
    {
        ok=0;
    }
}
int main()
{
    int a,b;
    while(~scanf("%d%d",&a,&b))
    {
        if(a==0&&b==0)
        {
            printf("Yes\n");
            continue;
        }
        for(int i=0;i<100005;i++)
        {
            f[i]=i;vis[i]=0;
        }
        if(a==-1&&b==-1)break;
        merge(a,b);
        ok=1;
        vis[a]=1;
        vis[b]=1;
        while(scanf("%d%d",&a,&b)&&a&&b)
        {
            merge(a,b);
            vis[a]=1;
            vis[b]=1;
        }
        if(ok==0)
        {
            printf("No\n");
            continue;
        }
        else
        {
            int cont=0;
            for(int i=0;i<=100005;i++)
            {
                if(vis[i]&&f[i]==i)
                cont++;
            }
            if(cont==1)
            {
                printf("Yes\n");
            }
            else
            {
                printf("No\n");
            }
        }
    }
}