首页 > 代码库 > poj1611 并查集 (路径不压缩)

poj1611 并查集 (路径不压缩)

http://poj.org/problem?id=1611

题目大意:

有一个学校,有N个学生,编号为0-N-1,现在0号学生感染了非典,凡是和0在一个社团的人就会感染,并且这些人如果还参加了别的社团,他所在的社团照样全部感染,求感染的人数。

 

解题思路:

并查集的变种,实质就是求0所在的强连通图的结点数目。

这道题纠结在数据的输入上,他只是告诉你哪些学生是同一个社团的。这就需要处理一下,我的想法是:如果这个社团有num个孩子,new出一个大小为num的数组,第一个孩子不处理,从第二个孩子起,和上个孩子合并,这样就完成了他们的合并。

 

AC代码:

#include<iostream>#include<cstdio>using namespace std;int p[30005],b[30005],r[30005],num[30005];int n,m,k;int Find(int x){    if(p[x]!=x) p[x]=Find(p[x]);    return p[x];}void Union(int x,int y){    //x=Find(x);    //y=Find(y);    if(x==y) return;    if(r[x]>r[y])    {        p[y]=x;        num[x]+=num[y];    }    else    {        p[x]=y;        if(r[x]==r[y]);        r[y]++;        num[y]+=num[x];    }}int main(){    while(scanf("%d%d",&n,&m)&&(m+n))    {        for(int i=0; i<n; i++)        {            p[i]=i;            r[i]=0;            num[i]=1;        }        while(m--)        {            scanf("%d",&k);            for(int i=1; i<=k; i++)                scanf("%d",&b[i]);            for(int i=1; i<k; i++)            {                int x=Find(b[i]);                int y=Find(b[i+1]);                Union(x,y);            }        }        int p=Find(0);        printf("%d\n",num[p]);    }    return 0;}

 

poj1611 并查集 (路径不压缩)