ACM算法:并查集

并查集的用途:并查集大多用在寻找同一类相关元素的题目中,更加通俗的讲,就是存在不同种类或者分类的

题目中。例如给定某图,让你计算存在几个不相邻的区域。又比如给定一个代表人的序列,让你确定这个人群

中存在几个小团体等等。这些问题都离不开其核心的东西,就是“不同类”。并查集就是在这种不同类问题中寻

找相同关系的集群,进而进行其他操作。


并查集的思路:并查集的思路很清晰,也很简单,但是我见网上有很多关于并查集的超详细的讲解,个人认为

,这么详细的讲解,对于并查集而言,没有必要。我在这理清一下并查集的思路,你就会很快地理解它。

在用途中说过,并查集一般用在“不同类”的问题中,所以它存在一个“找关系”的特点。说白的,并查集其实就是

将群集中的元素分为各个派别,在每个派别中存在上下级的关系,自然而然地,每个派别需要一个老大,而这个

老大就被当成这个派别的首领(也就是标志)。之后你在判断两个元素是否是同一个“派别”的时候,只要判断它

们的老大是否是同一个人就行,而这就是并查集的思想。说到这,你可能有那么一点感觉了,这里我在加上代码

的讲解,你就会一目了然了。


const int Max = 100;
//ves数组的下标代表群集中的每个元素,儿数组中存放的就是
//每个元素的上级,如果一个元素的上级是它自己,就说明这个
//元素是某一个“派别”的老大
int ves[Max];

/*
find函数就是用于找到每个元素的老大是否同一个的函数
*/
int find(int k)
{
	int temp = k;
	while (temp != ves[temp]) {
		temp = ves[temp];
	}

/*
其实一个普通的并查集中,find函数只要上面这一部分就可以了
之所以我们加上下面的这个while循环,是为了缩小上面的while
循环的循环次数。你仔细阅读下面这个代码就会知道,这个代码的
意义其实就是将一个派别中的所有成员的上级都直接变成这个派别
的老大。
*/
	int j,ptr = k;
	while (ves[ptr] != temp) {
		j = ves[ptr];
		ves[ptr] = temp;
		ptr = j;
	}

	return temp;
}

//这个函数是合并操作的,不用我多说你自己也看得明白吧
void join(int a, int b)
{
	int x = find(a);
	int y = find(b);

	if (x != y) ves[x] = y;
}


总结:当你理解了并查集之后,你就会知道这个算法是如此的简单,但它的思路很是巧

妙,而且用处确实很实用,是一种应该掌握的算法。



你可能感兴趣的:(ACM算法)