zoukankan      html  css  js  c++  java
  • 小鑫的城堡

    从前有一个国王,他叫小鑫。有一天,他想建一座城堡,于是,设计师给他设计了好多简易图纸,主要是房间的连通的图纸。小鑫希望任意两个房间有且仅有一条路径可以相通。小鑫现在把设计图给你,让你帮忙判断设计图是否符合他的想法。比如下面的例子,第一个是符合条件的,但是,第二个不符合,因为从5到4有两条路径(5-3-4和5-6-4)。

    Input

    多组输入,每组第一行包含一个整数m(m < 100000),接下来m行,每行两个整数,表示了一条通道连接的两个房间的编号。房间的编号至少为1,且不超过100000。

    Output

    每组数据输出一行,如果该城堡符合小鑫的想法,那么输出"Yes",否则输出"No"。

    Sample Input

    5
    2 5
    2 3
    1 3
    3 6
    4 6
    6
    1 2
    1 3
    3 4
    3 5
    5 6
    6 4

    Sample Output

    Yes
    No

    由题目"任意两个房间有且仅有一条路径可以相通"可知,不能成环并且所有給出的点必须相连,则可推:所给边的数量要等于所给点的数量减1。
    用并查集判断是否成环。
    用hash表记录所给点数。
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #define Maxn 100020
    using namespace std;
    char parent[Maxn];
    bool ha[Maxn];
    int flag;
    int Find(int x)
    {
        int r,temp;
        for(r=x; parent[r]>=0; r=parent[r]);
        while(r!=x)
        {
            temp=x;
            x=parent[x];
            parent[temp]=r;
        }
        return r;
    }
    void merge(int A,int B)
    {
        int a=Find(A),b=Find(B);
        if(a==b)
            flag=1;
        else
        {
            int temp=parent[a]+parent[b];
            if(parent[a]>parent[b])
            {
                parent[a]=b;
                parent[b]=temp;
            }
            else
            {
                parent[b]=a;
                parent[a]=temp;
            }
        }
    
    }
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            int a,i,b,m=0;
            flag=0;
            memset(ha,0,sizeof(ha));
            memset(parent,-1,sizeof(parent));
            for(i=0; i<n; i++){
                scanf("%d%d",&a,&b);
                if(ha[a]==0){
                    ha[a]=1;
                    m++;
                }
                if(ha[b]==0){
                    ha[b]=1;
                    m++;
                }
                merge(a,b);
            }
            if(m-1==n && !flag)
                printf("Yes
    ");
            else
                printf("No
    ");
        }
        return 0;
    }

    (测试证明,memset对bool型数组也适用)

    之后发现可以稍微优化一点:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #define Maxn 100020
    using namespace std;
    char parent[Maxn];
    int flag;
    int Find(int x)
    {
        int r,temp;
        for(r=x; parent[r]>=0; r=parent[r]);
        while(r!=x)
        {
            temp=x;
            x=parent[x];
            parent[temp]=r;
        }
        return r;
    }
    void merge(int A,int B)
    {
        int a=Find(A),b=Find(B);
        if(a==b)
            flag=1;
        else
        {
            int temp=parent[a]+parent[b];
            if(parent[a]>parent[b])
            {
                parent[a]=b;
                parent[b]=temp;
            }
            else
            {
                parent[b]=a;
                parent[a]=temp;
            }
        }
    }
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            int a,i,b;
            flag=0;
            memset(parent,-1,sizeof(parent));
            for(i=0; i<n; i++){
                scanf("%d%d",&a,&b);
                merge(a,b);
            }
            if(-parent[Find(a)]-1==n && !flag)
                printf("Yes
    ");
            else
                printf("No
    ");
        }
        return 0;
    }
  • 相关阅读:
    一些动规题
    洛谷P1717 钓鱼
    一堆递推题
    义冢oj P5033打气球
    义冢oj P5032生理周期
    Proud Merchants HDU
    739B
    Lost Cows POJ
    并查集负值根表集合大小的写法
    [Poi2011]Tree Rotations线段树合并
  • 原文地址:https://www.cnblogs.com/coder-tcm/p/9192520.html
Copyright © 2011-2022 走看看