杭電 hdu 1272 小希的迷宮【並查集】
阿新 • • 發佈:2019-01-24
小希的迷宮
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 38688 Accepted Submission(s): 11861
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");
}
}
}
}