POJ 1611 The Suspects 并查集

大学里总共有n个学生,m个社团。学生的编号从0到(n-1)。每个学生可以参加多个社团。现在0号学生疑似感染了SARS。与疑似感染者同一个社团的人都是疑似感染者。求疑似感染者总数。


这是一个简单的并查集题目。初始时,每个学生都各是一个集合。然后把同一社团的学生都合并到同一集合去。完成合并后,0号学生所在的集合的元素个数即是疑似感染者总数。


#include <stdio.h>
#define MAX 30005
//并查集
//还有一种设置并查集的办法:将father[]都初始化为-1,然后利用祖宗的father[]记录负的集合元素数。
int father[MAX];

int findset(int x)
{
    int fx = x,tmp;
    while(fx != father[fx])//找到x的最老的祖宗
        fx = father[fx];
    while(x != father[x])//路径压缩:把x的各级father都置为最老的祖宗
    {
        tmp = father[x];
        father[x] = fx;
        x = tmp;
    }
    return fx;
}

void unionset(int x,int y)
{
    x = findset(x);
    y = findset(y);
    if(x < y)//让编号最小的成为最老的祖宗,这是为了让0号学生成为代表元素
        father[y] = x;
    else
        father[x] = y;
    return;
}

int main()
{
    int m,n,k,i,j,suspects,tmp1,tmp2;
    //FILE *fp = NULL;
//    if(NULL == (fp = fopen("t.txt","r")) )
//        printf("cannot open file.\n");
    while(1)
    {
        suspects = 0;
        //fscanf(fp,"%d %d",&n,&m);
        scanf("%d %d",&n,&m);
        if(0 == m && 0 == n)
            break;
        if(0 == m)
        {
            suspects = 1;
            printf("%d\n",suspects);
            continue;
        }
        for(i=0;i<n;i++)//make set
            father[i] = i;
        for(i=0;i<m;i++)
        {
            //fscanf(fp,"%d",&k);
            scanf("%d",&k);
            //fscanf(fp,"%d",&tmp1);
            scanf("%d",&tmp1);
            for(j=1;j<k;j++)
            {
                //fscanf(fp,"%d",&group[j]);
                scanf("%d",&tmp2);
                unionset(tmp1,tmp2);
            }
        }
        for(i=0;i<n;i++)
            //if(0 == father[i])
            if(0 == findset(i))
                suspects++;
        printf("%d\n",suspects);
    }

    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值