杭电ACM 1232 畅通工程

这个题大家一看到可能就会想到用并查集,高手们都用这种方法解决这个问题。像我,刚刚学习编程不久,还不知道什么是并查集,

所以我就自己写了个解决方法。

我的思路是  帮所有可以相通的城市化为一个城市群,称之为层。这个题的关键就是求出所有的层,添加最少的道路即为层数减一条。

从输入开始,如果这两个城在之前都没有城市可以通达,则化为一个新层,层数加一;若其中有一个城市出现,则把没有出现的城市化

为已经出现的那个城市所在的层;如果都出现了,它们所在的层不同则进行替换,注意这里的替换是替换所有的相同的层数,详细可见

相应的代码区。

本来我以为就对了,可是这个题貌似还有非法数据,

比如

3 1

5 6

像这样的输入,我的程序就会出错,我的程序跑出来的是2,可正确结果是1。不过我们的思路是对的。我们只需要在出现新层,出现之前

无道路可通达的新城市,和出现的城市所在的层不同处,增加一条语句“MinAdd --”MinAdd 初始化城市数减一。其原因是,每当有道路存在

时,我们就可以少修一道路。好了 说了这么多,应该懂了,不懂的话可以在联系我。

此题URL http://acm.hdu.edu.cn/showproblem.php?pid=1232

这是我自己写的非并查集代码,可能有点长,但同样效率不低。

#include "stdio.h"
#include "string.h"

int
main()
{

    int
city,road,i,j,a,b,temp;
    int
CityRoad[1001],floor[1001];
    int
MinAdd,part,ans;
    while
(scanf("%d%d",&city,&road),city)
    {

        memset(CityRoad,0,sizeof(CityRoad));
        memset(floor,0,sizeof(floor));
        part = 0;
        MinAdd = city-1;
        for
(i = 0; i < road; i ++)
        {

            scanf("%d%d",&a,&b);
            if
(CityRoad[a] == 0 && CityRoad[b] == 0) //两个城市第一次出现是一个新层
            {
                part ++;
                floor[part] = part;//记录当前层数
                CityRoad[a] = part;//记录层数和标识此城市已有道路通达
                CityRoad[b] = part;//记录层数和标识此城市已有道路通达
                MinAdd--;
            }

            else

            {

                if
(CityRoad[a] == 0 && CityRoad[b] != 0)
                {

                    CityRoad[a] = CityRoad[b];
                    MinAdd--;
                }

                else if
(CityRoad[a] != 0 && CityRoad[b] == 0)
                {

                    CityRoad[b] = CityRoad[a];
                    MinAdd--;
                }

                else if
(CityRoad[a] != 0 && CityRoad[b] != 0)
                {

                    if
(floor[CityRoad[a]] > floor[CityRoad[b]])
                    {

                        temp = floor[CityRoad[a]];   
                        for
(j = 1; j < part + 1; j ++)
                        {

                            if
(floor[j] == temp)
                            {

                                floor[j] =  floor[CityRoad[b]];  //两个层之间有相通的城市,因而可以归为一个层
                            }
                        }

                        MinAdd--;
                    }

                    else if
(floor[CityRoad[a]] < floor[CityRoad[b]])
                    {

                        temp = floor[CityRoad[b]];   
                        for
(j = 1; j < part + 1; j ++)
                        {

                            if
(floor[j] == temp)
                            {

                                floor[j] =  floor[CityRoad[a]];  //两个层之间有相通的城市,因而可以归为一个层
                            }
                        }

                        MinAdd--;
                    }
                }
            }
        }

        printf("%d\n",MinAdd);
    }
}

这是我一朋友AC过的并查集代码 比较简洁,高效。

#include <stdio.h>
#define NUM 1000
int pre[NUM];

void
reset()
{

    for
(int i=0;i<NUM;i++)
        pre[i] = i;
}


int
find_pre(int i)
{

    if
(pre[i]!=i)
        pre[i] = find_pre(pre[i]);
    return
pre[i];
}


int
append(int a, int b)
{

    int
pre_a, pre_b;
    pre_a = find_pre(a);
    pre_b = find_pre(b);
    if
(pre_a == pre_b) return 0;
    pre[pre_a] = pre_b;
    return
1;
}


int
main()
{

    int
N,M,ans,a,b,i;
    while
(scanf("%d",&N),N)
    {

        scanf("%d",&M);
        reset();
        ans = N-1;
        for
(i=0;i<M;i++)
        {

            scanf("%d%d",&a,&b);
            if
(append(a,b)) ans--;
        }

        printf("%d\n",ans);
    }
}

posted @ 2011-06-16 13:27  ProgrammingEveryday  阅读(641)  评论(0编辑  收藏  举报