1272(translate 并查集)

并查集。题目要求的迷宫有两个特点:1:无环、2:单根,因此,若同一边上的两个点拥有相同的父节点,则可以认为有环,最后加一个扫描,判断根节点个数。

若一条边的两个节点为同一个父节点,则成环。若所有的节点的父节点相同则联通。注意输入0 0时为Yes。

拓展:改为有向图hdu1325

1:保证图是连通的,且连通分量为1( 即从一点可以到任意一点 )

2:不存在环(包括自环)

因为这是一个无向图,只要保证 顶点数 = 边数+1 , 就可以说明是连通的。如果存在1->2 , 2->3 , 1->3这样的图话,虽然满足了左面的公式,但是已经成了环,所以也不会影响到最后的判断。

#include<bits/stdc++.h>
using namespace std;
const int M= 100005;
int a,b;
int father[M];       //记录父节点
bool circle;         //判断是否存在环
bool visit[M];       //用来记录顶点数
int edgenum,pointnum;    //分别表示边数,顶点数
void init( )
{
    for( int i=0 ; i<M ; i++ )
        father[i] = i,visit[i]=false;
    circle = false;
    edgenum = pointnum = 0;
}
int Find(  int x )
{
    return x==father[x]?x:father[x]=Find(father[x]);
}
    void unin( int a,int b )
    {
        if(a==b)
            circle = true;
        int x, y;
        x = Find(a);
        y = Find(b);
        if( x != y )
        {
            father[x] = y;
            edgenum++;       //引出一条边
        }
        else
            circle = true;   //x==y,说明他们是同一个祖先,一旦连通便与祖先3者成环
    }

    int main()
    {
        while( true )
        {
            init( );
            scanf("%d%d",&a,&b);
            if( a==0 && b==0 )      //为空树
            {
                printf("Yes\n");
                continue;
            }
            if( a==-1 && b==-1 )
                break;
            visit[a] = true;
            visit[b] = true;
            unin( a,b );
            while( true )
            {
                scanf("%d%d",&a,&b);
                if( a==0 && b==0 )
                    break;
                visit[a] = true;
                visit[b] = true;
                unin( a, b );
            }
            for( int i=0 ; i<M ; i++ )
                if( visit[i] )
                    pointnum++;
            if(  !circle && edgenum+1 == pointnum )
                printf("Yes\n");
            else
                printf("No\n");
        }
        return 0;
    }



#include<bits/stdc++.h>
using namespace std;
const int  N=100000+5;
bool circle;//判断是否形成个环
int fa[N];
int Find(int x)//爆栈就是在这里
{
    if(fa[x]!=x) fa[x]=Find(fa[x]);
    return fa[x];
}
void uni(int x,int y)
{
    int xx=Find(x);
    int yy=Find(y);
    if(xx!=yy)
        fa[xx]=yy;
    else
        circle=true;  //第一次合并绝对不会出现环
    //只有游乐环才会第二次合并。
}
void init()
{
    for(int i=1; i<N; i++)
        fa[i]=i;
}
int main()
{
    set<int>s;//至于这个set容器可以用来找顶点,在这个容器里重复的数字只计一次
    int a,b,sum;//sum计算边
    while(scanf("%d %d",&a,&b)!=EOF)
    {
        init();
        sum=1,circle=false;
        if(a==0&&b==0)//这也是一个比较坑的地方
        {
            printf("Yes\n");
            continue;
        }
        if(a==-1&&b==-1)
            break;
        s.insert(a);
        s.insert(b);
        if(!circle)
            uni(a,b);
        while(1)
        {
            scanf("%d %d",&a,&b);
            if(a==0&&b==0)
                break;
            s.insert(a),s.insert(b);
            if(!circle)
                uni(a,b);
            sum++;
        }
        if(!circle&&s.size()==sum+1)
            printf("Yes\n");
        else
            printf("No\n");
        s.clear();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/beposit/article/details/80616948