hdu 1232 畅通工程

2012-11-23

今天复习了一下并查集,然后这道题才发现当时是傻掉了,其实就是并查集找有多少个连通分量,有c个连通分量的话要把他们连起来就需要c-1条边,根本不需要kruskal算法…………………………

#include <cstdio>
#include <cstring>
#define N 1010
int p[N];
int n,m;

int find(int x)
{  return p[x]==x ? x : p[x]=find(p[x]);  }
int main()
{
    while(scanf("%d",&n) && n)
    {
        for(int i=1; i<=n; i++)
            p[i]=i;
        scanf("%d",&m);
        for(int i=1; i<=m; i++)
        {
            int u,v,x,y;
            scanf("%d%d",&u,&v);
            x=find(u);
            y=find(v);
            if(x!=y)
                p[x]=y;
        }
        int count=0;
        for(int i=1; i<=n; i++)
            if(p[i]==i)
                count++;
        printf("%d\n",count-1);
    }
    return 0;
}

//最小生成树裸题

//给出已经存在的边(输入中可能重复但是不影响),然后问你要构建出最小生成树还需要//多少条边

//用kruskal算法显然更合理并且方便,已经存在的边保存在边集数组中,然后看看这些已

//经存在的边有多少条是可以纳入的(因为已经存在的边如果全部纳入的话可能有环)

//没纳入一条边我们就在count中计数,扫描完边集数组后,就可以已经纳入了多少条边

//即count,然后还需要的边就是n-1-count,因为由最小生成树的性质可知边数一定是n-1

//题目很容易,不要进去惯性思维与权值扯上关系,这道题与权值无关,其实是考察了最小//生成树成环的问题,边集数组中只需要保存边的两个点即可,不需要知道权值

#include <stdio.h>
#include <string.h>
#define MAX 1100
struct edge
{
    int b,e;
}a[MAX*MAX];
int count,n,m;
int p[MAX];

int find(int x)
{  return p[x]==x ? x : p[x]=find(p[x]) ;  }

int main()
{
    int i,j,x,y;
    while(scanf("%d",&n)!=EOF && n)
    {
        scanf("%d",&m);
        for(i=1; i<=m; i++) scanf("%d%d",&a[i].b,&a[i].e);

        for(i=1; i<=n; i++) p[i]=i;

        for(count=0,i=1; i<=m; i++)
        {
            x=find(a[i].b);
            y=find(a[i].e);
            if(x!=y)
            {
                p[x]=y;
                count++;
            }
        }

        printf("%d\n",n-1-count);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/scau20110726/p/2724877.html