POJ611 The Suspects并查集+优先队列

POJ1611


题目大意: 非典来袭 n 个人 m 个团队, n个人的编号为0 --- n-1 其中已知 0 被怀疑携带非典病毒,如果一个队伍中有一个人是

被怀疑携带有此病毒,那么这一个团队中的所有人都被i怀疑携带有非典病毒。

输入格式:

第一行 n m 代表 n个人 m个团队

接下来的m行 每一行代表一个团队  每一行的第一个数为团队人数  后面接上 此团队的人员编号

直到输入中 n m全为0  方才结束。

输出:所有可能携带次病毒的人员的数量。

解析:很明显 用并查集  另外 考虑一下极端情况 

如果输入的数据为:

30000 1

3 0 29999 15000

0 0

那么 真是哦存在的只有三个人 0 15000 29999 如果i循环从0一个一个枚举 则不太好 

好一点的方法就是用优先队列 将这三个数存储起来  用的时候 一个一个弹出 即可。

代码C:

# include <stdio.h>
# define N 30001
void insert(int Tree[],int X);//向堆中插入值 S[WEI]
int Delmin(int Tree[]);       //删除堆头-并返回堆头
int find(int x);
void Link(int x,int y);
int tree[N+1];  //堆
int p[N],Q[N];
int main()
{
    int n,m,a,b,c,i,j,k;
  //  freopen("AAA.txt","r",stdin);
    while(scanf("%d%d",&n,&m)&&(n||m))
    {
        while(m--)
        {
            scanf("%d%d",&a,&c);
            c++;
            Link(c,c);
            while(--a>0){
                scanf("%d",&b);
                if(find(++b)!=c)Link(b,c);
            }
        }
        n=0;
        while(tree[0])Q[n++]=Delmin(tree);
            for(i=k=0,c=find(1); i<n; i++)
                if(p[Q[i]])
                {
                    if(find(Q[i])==c)tree[++k]=Q[i];
                    else p[Q[i]]=0;
                }
        if(k)printf("%d\n",k);
        else printf("1\n");
        while(k)p[tree[k--]]=0;
    }
    return 0;
}
void insert(int Tree[],int X)//向最小堆中插入X
{
    int par,i=++Tree[0];            //插入X 后 Tree[0]+1
    while(i>1)                      //直到i不是根节点
    {
        par=(i>>1);                 //父节点为par
        if(Tree[par]<=X) break;     //将<=改为>=即改为最大堆了
        Tree[i]=Tree[par];          //否则调整堆 即位置上移
        i=par;
    }
    Tree[i]=X;                      //插入新节点
}
int Delmin(int Tree[])
{
    int i=1,L=2,root=Tree[1],X=Tree[Tree[0]--];
    while(L<=Tree[0])
    {
        L+=L<Tree[0]&&Tree[L+1]<Tree[L];
        if(Tree[L]>=X) break;
        Tree[i]=Tree[L];
        i=L;
        L=i<<1;
    }
    Tree[i]=X;
    return  root;
}
int find(int x)
{
    int y=x;
    if(p[x])while(x!=p[x]) x=p[x];
    else insert(tree,x);
    return p[y]=x;
}
void Link(int x,int y)
{
    p[find(x)]=find(y);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值