zoukankan      html  css  js  c++  java
  • 并查集--小鑫的城堡

    小鑫的城堡

    Time Limit: 1000MS Memory limit: 65536K

    题目描述

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

    输入

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

    输出

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

    示例输入

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

    示例输出

    Yes

    No

     

    注意:1.此题运用并查集便可以做,最重要的一点是要先求出点的个数(详见程序),再依据:如果点的个数n等于边的条数m加1,就可保证任意两个点之间有且仅有一条路径可以相通。

                2.刚开始时没想到如何求点的个数,这是一个难点,还有我把if(k == m + 1) 写成了if(k = m + 1) 调试了很久,这个错误出现了很多回,所以这里写一下,避免重蹈覆辙。

                3.再说一下吧:测点的数目不好弄,因为如果输入的点没有1,只有2,3,4,5,6,不用a数组标记一下的话,在这里for(i = 1; i <= max; i++)  {  if(a[i]==1) { k++; } } k就会被 多加了一次,就错了,第一次做时,忽略了必须得满足任意两点只之间都得有通路,就是下文的c,不明白可以看看第三组测试数据。

     正确代码:

    #include<stdio.h>
    #include<string.h>
    int bin[100002], a[1000002];//a数组为标记数组
    int findx(int x)
    {
        int r=x;
        while(bin[r] !=r)
            r=bin[r];
        return r;
    }
    void merge(int x,int y)
    {
        int fx,fy;
        fx = findx(x);
        fy = findx(y);
        if(fx != fy)
            bin[fx] = fy;
    }
    int main()
    {
        int m ,i, k, c, N, M;//m为边数,N,M表示每条边的两顶点。
        int max;
        while(~scanf("%d", &m))
        {
            max = 0;
            memset(a, 0, sizeof(a));//注意清零
            for(i=1;i<=100002;i++)
                bin = i;
            for(i = 0; i < m; i++)
            {
                scanf("%d %d", &N, &M);
                merge(N, M);
                if(max < N) max = N;//if语句是为求出m组输入数据中最大的点。
                if(max < M) max = M;
                a[N] = 1;//如果点被输入,则标记一下,为下面求k的值做准备。
                a[M] = 1;
            }
            k = 0, c = 0;//k 表示总共输入的点的个数,从0开始,
                        //c变量是为判断此图两个点是否最起码有一条路径可以相通
            for(i = 1; i <= max; i++)
            {
                //printf("bin[%d] = %d
    ", i, bin);  此处消除注释,便得测试结果
                if(a==1)
                    k++;
                if(bin == i && a)
                    c++;
            }
           if(c==1 && k == m + 1)//如果c等于1,则说明途中路全通,当路不全通时,c会大于1.
                                 //当然c=1;只是其中一个条件,因为当图中点与点之间都联通时,
                                 //假设其中有两个点之间有2条路可通,此时的c也等于1,但不满
                                 //足"任意两个点有且仅有一条路径可以相通"这一条件,所以还需
                                 //加上 k == m + 1 这一条件,(字母含义详见代码)
                printf("Yes
    ");
           else
                printf("No
    ");
        }
          return 0;
    }
    
    以下为题目中测试数据:
    5
    2 5
    2 3
    1 3
    3 6
    4 6
    bin[1] = 3
    bin[2] = 5
    bin[3] = 6
    bin[4] = 6
    bin[5] = 3
    bin[6] = 6
    Yes  此时只有bin[6] = 6, 所以此时c为1, 而又满足 k = m + 1, 所以Yes
    再看下组数据:
    5
    2 5
    2 3
    1 3
    3 6
    4 6
    bin[1] = 3
    bin[2] = 5
    bin[3] = 6
    bin[4] = 6
    bin[5] = 3
    bin[6] = 6
    No   此时也只有b[6] = 6, 但不满足 k = m + 1,所以No,
    
    在这里在加上一组数据(此时c不为1,但满足 k = m + 1(这种情况为任意两个点不满足有且仅有一条路径可以相通,可能有两点不通)):
    4
    1 2
    3 4
    3 5
    4 5
    bin[1] = 2
    bin[2] = 2
    bin[3] = 4
    bin[4] = 5
    bin[5] = 5
    No  此时c为2, 因为bin[2] = 2和bin[5] = 5, 而k为5,m为4,满足k = m + 1;
    
    

    这下应该懂了^~^    

     
    每天训练发现我比别人做的好慢,但是理解的更深刻,如果一开始学一个新知识点就搜模板,那么这样的人是走不远的,毕业之后带走的只有思维,什么荣誉,奖杯都已经不重要了。
  • 相关阅读:
    Openstack API 开发 快速入门
    virtualBox虚拟机到vmware虚拟机转换
    使用Blogilo 发布博客到cnblogs
    Openstack Troubleshooting
    hdoj 1051 Wooden Sticks(上升子序列个数问题)
    sdut 2430 pillars (dp)
    hdoj 1058 Humble Numbers(dp)
    uva 10815 Andy's First Dictionary(快排、字符串)
    sdut 2317 Homogeneous squares
    hdoj 1025 Constructing Roads In JGShining's Kingdom(最长上升子序列+二分)
  • 原文地址:https://www.cnblogs.com/6bing/p/3931274.html
Copyright © 2011-2022 走看看