您的位置:首页 > 其它

图论中的并查集

2014-05-12 19:22 162 查看
来源 http://www.cnblogs.com/cyjb/p/UnionFindSets.html
并查集(Union-find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题。一些常见的用途有求连通子图、求最小生成树的
Kruskal 算法和求最近公共祖先(Least Common Ancestors, LCA)等。

使用并查集时,首先会存在一组不相交的动态集合 S={S1,S2,⋯,Sk},一般都会使用一个整数表示集合中的一个元素。

每个集合可能包含一个或多个元素,并选出集合中的某个元素作为代表。每个集合中具体包含了哪些元素是不关心的,具体选择哪个元素作为代表一般也是不关心的。我们关心的是,对

于给定的元素,可以很快的找到这个元素所在的集合(的代表),以及合并两个元素所在的集合,而且这些操作的时间复杂度都是常数级的。

并查集的基本操作有三个:

makeSet(s):建立一个新的并查集,其中包含 s 个单元素集合。
unionSet(x, y):把元素 x 和元素 y 所在的集合合并,要求 x 和 y 所在的集合不相交,如果相交则不合并。
find(x):找到元素 x 所在的集合的代表,该操作也可以用于判断两个元素是否位于同一个集合,只要将它们各自的代表比较一下就可以了。

using namespace std;
const int MAXSIZE=500;
int uset[MAXSIZE];
int rank[MAXSIZE];
void makeSet(int size)
{
	for(int i=0;i<size;i++)
	{
		uset[i]=i;
		rank[i]=0;//当前的深度
	}
}

int find(int x)
{
	int p=x,t;
	while(uset[p]!=p) p=uset[p];
	while(x!=p){t=uset[x];uset[x]=p;x=t;}//使得一个集合的元素都指向根
	return x;
}

void unionset(int x,int y)
{
	if((x=find(x))==(y=find(y))) return;
	if(rank[x]>rank[y]) uset[y]=x;
	else
	{
		uset[x]=y;
		if(rank[x]==rank[y]) rank[y]++;
	}
}
实例:



代码如下:

int friends(int n,int m,int r[5][5])
{
	makeSet(n);
	set<int> i_set;
	int i,j;
	for(i=1;i<=n;i++)
		for(j=i+1;j<=n;j++)
		{
			if(r[i-1][j-1]==1)
			{
				unionset(i-1,j-1);
			}
		}
	int res=0;
	for(i=0;i<n;i++)
	{
		//i_set.push_back(uset[i]);
		i_set.insert(uset[i]);
	}
	return i_set.size();
}
int _tmain(int argc, _TCHAR* argv[])
{	int n=5;
	int m=3;
	int r[5][5]={0};
	r[0][1]=1;
	r[1][2]=1;
	r[3][4]=1;
	cout<<friends(n,m,r);
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: