北大acm 1611,2524解题报告--关于并查集

    这两道题都是比较简单的关于并查集使用的题目。有关并查集的知识,请参考:

   (1) http://www.cnblogs.com/ACShiryu/archive/2011/11/24/unionset.html

   (2)http://www.cnblogs.com/mikelin/archive/2010/08/11/1797556.html

   其中:我们可以利用下面这段模板代码,做到熟记于心,即使变形也有思路

   

const int N=100;
int pa[N];
int rank[N];
long int cnt;


void make_set(int n)
{
	for (int x=0;x<n;x++)
	{
		pa[x] = x;
		rank[x] = 0;
	}
}
int find_father(int x)
{
	if(x != pa[x])
		pa[x] = find_father(pa[x]);
	return pa[x];
}

void union_set(int x, int y)
{
	x = find_father(x);
	y = find_father(y);

	if (x==y)
	{
		return;
	}
	if(rank[x] > rank[y])
		pa[y] = x;
	else
	{
		pa[x] = y;
		if(rank[x] == rank[y])
			rank[y]++;
	}
}

    比如1161题:http://poj.org/problem?id=1611

   只需要把上面的N改成需要的50000;

   1161题代码:

  

1161
#include <iostream>
#include <cstdio>
using namespace std;

const int N=50000;
int pa[N];
int rank[N];   


void make_set(int n)
{
	for (int x=0;x<n;x++)
	{
		pa[x] = x;
		rank[x] = 0;
	}
}
int find_father(int x)
{
	if(x != pa[x])
	  pa[x] = find_father(pa[x]);
	return pa[x];
}

void union_set(int x, int y)
{
	x = find_father(x);
	y = find_father(y);
	if(rank[x] > rank[y])
		pa[y] = x;
	else
	{
		pa[x] = y;
		if(rank[x] == rank[y])
			rank[y]++;
	}
}
int main()
{
	int n,m,i,j,cnt;
	while (1)
	{
		cnt=0;
		scanf("%d %d",&n,&m);
		make_set(n);
		if (n==0 && m==0)
			break;

		for (i=0;i<m;i++)
		{
			int y=-1;
			int num;
			scanf("%d",&num);
			for (j=0;j<num;j++)
			{
				int x;
				scanf("%d",&x);	
				if (y!=-1)
				   union_set(x,y);
				y=x;	
			}
		}
		int r=find_father(0);

		for (i=0;i<n;i++)
		{
			if(r==find_father(i))
				cnt++;
		}
		printf("%d\n",cnt);
	}	
	return 0;
}


 

   代码很简洁,类似的2524题:http://poj.org/problem?id=2524

#include <iostream>
#include <cstdio>
using namespace std;

const int N=50001;
int pa[N];
int rank[N];
long int cnt;


void make_set(int n)
{
	for (int x=1;x<n+1;x++)
	{
		pa[x] = x;
		rank[x] = 0;
	}
}
int find_father(int x)
{
	if(x != pa[x])
		pa[x] = find_father(pa[x]);
	return pa[x];
}

void union_set(int x, int y)
{
	x = find_father(x);
	y = find_father(y);

	if (x==y)
	{
		return;
	}
	if(rank[x] > rank[y])
		pa[y] = x;
	else
	{
		pa[x] = y;
		if(rank[x] == rank[y])
			rank[y]++;
	}
}
int main()
{
	long int n,m,i;
	long int c=1;
	while (1)
	{
		scanf("%ld %ld",&n,&m);
		cnt=0;
		make_set(n);
		if (n==0 && m==0)
			break;

		for (i=0;i<m;i++)
		{
			long int x,y;
            scanf("%d %d",&x,&y);
			union_set(x,y);
		}
		for(i=1;i<=n; i++)
			if(pa[i] == i)
				cnt++;
		printf("Case %ld: %ld\n",c,cnt);
		c++;
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值