【并查集】:poj1611,The Suspects

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



题目大意:

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


注意,并查集Find操作:

不进行路径压缩:return Find(a[i].parent)

进行路径压缩:a[i].parent=Find(a[i].parent); return a[i].parent;  不要用while循环!!!





# include<iostream>
using namespace std;

# define N 30003

struct STUDENT
{
	int parent;
	int size;
};
STUDENT student[N];

void MakeUnionFind(int n)
{
	for(int i=0;i<n;i++)
	{
		student[i].parent=i;
		student[i].size=1;
	}
}

int FindParent(int i)
{
	/*
	while(student[i].parent!=i)
	{
		student[i].parent=FindParent(student[i].parent);
	}
	return student[i].parent;
	*/
	if(student[i].parent==i)
	{
		return i;
	}
	else
	{
		//return FindParent(student[i].parent); no path compression
		//do path compression, 注意,不能使用上面的循环!!!
		student[i].parent=FindParent(student[i].parent);
		return student[i].parent;
	}
}

void Union(int i, int j)
{
	int ip=FindParent(i);
	int jp=FindParent(j);
	if(ip!=jp)
	{
		if(student[ip].size<student[jp].size)
		{
			student[ip].parent=jp;
			student[jp].size+=student[ip].size;
		}
		else
		{
			student[jp].parent=ip;
			student[ip].size+=student[jp].size;
		}
	}
}

int main()
{
	int n,m,k;
	int i,j,t1,t2;
	while(true)
	{
		cin>>n>>m;
		if(n==0 && m==0)
		{
			break;
		}

		MakeUnionFind(n);

		for(i=1;i<=m;i++)
		{
			cin>>k>>t1;
			for(j=2;j<=k;j++)
			{
				cin>>t2;
				Union(t1,t2);
			}
		}

		cout<<student[student[0].parent].size<<endl;
	}
	return 0;
}




注意下面的错误:

for(i=1;i<=m;i++)
        {
            cin>>k>>t;
            //不应该把这个放到外面,因为在之后的union过程中,t的parent可能会改变
            //tp=FindParent(t);
            for(j=2;j<=k;j++)
            {
                cin>>tt;
                tp=FindParent(t);
                ttp=FindParent(tt);
                if(tp!=ttp)
                {
                    Union(tp,ttp);
                }
            }
        }


# include<iostream>
using namespace std;

# define N 30005

struct NODE
{
    int p,s;
};

NODE node[N];

void MakeSet(int n)
{
    for(int i=0;i<=n;i++) //start from "0"
    {
        node[i].p=i;
        node[i].s=1;
    }
}

int FindParent(int t)
{
    if(t==node[t].p)
    {
        return t;
    }
    else
    {
        int tp=node[t].p;
        node[t].p=FindParent(tp);
        return node[t].p;
    }
}

void Union(int tp, int ttp)
{
    if(node[tp].s<node[ttp].s)
    {
        node[tp].p=ttp;
        node[ttp].s+=node[tp].s;
    }
    else
    {
        node[ttp].p=tp;
        node[tp].s+=node[ttp].s;
    }
}

int main()
{
    int n,m,k,i,j,t,tt,tp,ttp;
    while(true)
    {
        cin>>n>>m;
        if(n==0 && m==0)
        {
            break;
        }

        MakeSet(n);

        for(i=1;i<=m;i++)
        {
            cin>>k>>t;
            //不应该把这个放到外面,因为在之后的union过程中,t的parent可能会改变
            //tp=FindParent(t);
            for(j=2;j<=k;j++)
            {
                cin>>tt;
                tp=FindParent(t);
                ttp=FindParent(tt);
                if(tp!=ttp)
                {
                    Union(tp,ttp);
                }
            }
        }
        cout<<node[FindParent(0)].s<<endl;
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值