POJ1611(The Suspects)又见并查集

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

这貌似我做的第二道并查集的题,算是一道水题吧,题目的大概意思是找出与编号为0的人有

交集的人数。所以要将出现的集合中有交集的合并成大集合,最后输出0所在集合的人数。

 

贴代码:

 

#include<iostream>
using namespace std;
#define N 30005

int p[N],f[N];//f用来存集合元素的个数

int find(int x)//并查集的根本,找父亲结点
{
return p[x] == x ? x : ( p[x] = find(p[x]) );
}

void merge(int a, int b)
{
int x = find(a);
int y = find(b);
/*照顾0,所以把小的数作为父亲结点*/
if(x < y) {
p[y] = x;
f[x] += f[y];
}
else if(x > y) { //这里不能写else,因为x=y无需处理
p[x] = y;
f[y] += f[x];
}
}

int main()
{
int n,m;
int k,a,b;
while(cin >> n >> m,n || m)
{
/*初始化并查集 */
for(int i = 0; i < n; i++)
{
p[i] = i;
f[i] = 1;
}
while( m--)
{
cin >> k;
cin >> a;
for(int j = 1; j < k; j++)
{
cin >> b;
merge(a,b);//合并集合
}
}
cout << f[0] << endl;//输出0所在集合元素个数
}
return 0;
}


   
可能是merge函数写的不够好,所以跑了63ms...

 现在又写了一遍:

/*Accepted    408K    0MS    C++    927B    2012-07-27 16:24:33*/

#include<cstdio>



const int MAXN = 300101;

int p[MAXN], cnt[MAXN];



int find_set( int x)

{

    return p[x] = p[x] == x ? x : find_set(p[x]);

}



void union_set( int x, int y)

{

    int nx = find_set(x), ny = find_set(y);

    if( nx < ny){ //以编号小的点为根

        p[ny] = nx;

        cnt[nx] += cnt[ny];

    }

    else if(nx > ny) {

        p[nx] = ny;

        cnt[ny] += cnt[nx];

    }

}



int main()

{

    int n, m, k;

    while( scanf( "%d%d", &n, &m), n || m)

    {

        for( int i = 0; i < n; i ++)

        {

            p[i] = i;

            cnt[i] = 1;

        }

        while( m --)

        {

            int x, y;

            scanf( "%d", &k);

            scanf( "%d", &x);

            for( int i = 1; i < k; i ++)

            {

                scanf( "%d", &y);

                union_set(x, y);

            }

        }

        printf( "%d\n", cnt[0]);

    }

    return 0;

}

你可能感兴趣的:(poj)