hdu1272(并查集的运用)

上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走。但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了房间A和B,那么既可以通过它从房间A走到房间B,也可以通过它从房间B走到房间A,为了提高难度,小希希望任意两个房间有且仅有一条路径可以相通(除非走了回头路)。小希现在把她的设计图给你,让你帮忙判断她的设计图是否符合她的设计思路。比如下面的例子,前两个是符合条件的,但是最后一个却有两种方法从5到达8。

大意就是说无向图中没有环且图连通,当然不能用拓扑排序的方法了,因为10000的数据量且边的多少也没法确定,判断方法就是并查集,如果a-b且b-c那么现在a-c相连就会构成回路.放入并查集的模型如下:

     t1=find(b);
     t2=find(c);
     if (t1!=t2)
     pre[t2]=t1;
     else
      flag=0;//否则a-b相连,b-c相连,然后a-b又相连,形成环.
哪怕是特殊数据比如1-2,2-1那也构成了环,一开始没想清楚.

最后判断连通就没必要在BFS了,因为连通必然会导致所有点的根节点都是同一个点,先取find(第一个被访问的点)再看看和后面find(被访问的点)是否相等,当然需要一个vis记录下被访问的点.

给几个测试用例:

0 0 yes
1 1 0 0 yes
1 2 2 1 0 0 no

#include <stdio.h>
#include <string.h>
int pre[100005];
int vis[100005];
int n,m,flag;
int find(int i)
{
     int j=i,temp;
     while (pre[i]!=i)
        i=pre[i];
     while (j!=i)
     {
         temp=pre[j];//先记录下下一个长官
         pre[j]=i;//统一都更新为i的手下
         j=temp;//迭代
     }
     return i;
 }
 void merge(int b,int c)
 {
     int t1,t2;
     if (b==c)
     return;
     t1=find(b);
     t2=find(c);
     if (t1!=t2)
     pre[t2]=t1;
     else
      flag=0;//否则a-b相连,b-c相连,然后a-b又相连,形成环.
    return;
}
 int main()
 {
    int i,j,a,b,k,t;
    while(scanf("%d%d",&a,&b)==2&&(a!=-1||b!=-1))
    {
        flag=1;
        memset(vis,0,sizeof(vis));
        for (i=1;i<=100005;i++)
        pre[i]=i;
        merge(a,b);
        vis[a]=1;
        vis[b]=1;
        if ((a==0)&&(b==0))
        {
         printf("Yes\n");
         continue;
        }
        while(scanf("%d%d",&a,&b)==2&&(a!=0||b!=0))
        {
            merge(a,b);
            vis[a]=1;
            vis[b]=1;
        }
        j=1;
        while(vis[j]==0)
        j++;
        k=find(j);
        for (i=j+1;i<=100000;i++)
        if ((vis[i])&&(find(i)!=k))
        {
            flag=0;
            break;
        }
        if (flag)
        printf("Yes\n");
        else
        printf("No\n");
    }
    return 0;
 }



你可能感兴趣的:(hdu1272(并查集的运用))