并查集是一个高效的数据结构,最简单的作用是用来判断图中的两个点是不是属于同一个连通分量。
我们可以将图中的每一个连通分量看成一个集合,每个集合都有一个特征值。比如{1,2,3,4}的特征值为1,那么记f[1] = f[2] = f[3] = f[4] = 1,则这样可以通过判定两个点的f值来判定是不是属于同一个连通分量。
然后,我们用树的形式来记录集合,并且这个树只需要包含集合中的所有点即可,而不需要在意树的具体形式。而这个集合的特征值,则为根节点的节点编号。这样的话,如果该树是条长长的链,则每次求叶子节点的f值时都需要几乎遍历所有节点,这样的话时间复杂度就会很高。所以,我们每次求了一个点的f值都将该节点的父亲设置为树的根节点(即改变树的形状)。
下面是find函数:
1 //find返回节点x的父亲节点 2 int find(int x) 3 { 4 if (x != f[x]) f[x] = find(f[x]); 5 return f[x]; 6 }
下面是merge函数:
1 //将不属于同一个连通分量的两点x,y所在的连通分量合并 2 void merge(int x, int y) 3 { 4 int t1 = find(x), t2 = find(y); 5 f[t1] = t2; 6 }
题目训练:
1、POJ 1861 Network
水题,裸的最小生成树的Kruskal算法改一下。题解POJ 1861 Network。
2、POJ 2524 Ubiquitous Religions和POJ 1611 The Suspects
两道水题,算是并查集入门题吧。
3、POJ 1703 Find them, Catch them
并查集的基础题,很多难题都是以这种思路为来做的。感觉这道题完全弄懂以后,就算是会并查集了。题解POJ 1703 Find them, Catch them。
4、POJ 1182 食物链
并查集的基础题,是上一道题(POJ 1703)的加强版。算是很经典的题了。题解POJ 1182 食物链。
5、LA 3644
巧妙之处在与建图,(至少对于我这种图论小白来说),图建好了就是以罗并查集。题解LA 3644 X-Plosives。
6、POJ 1456 Supermarket
贪心+并查集优化。很好的并查集使用方法,还有SRM 473 div1 500pt,就是数学+并查集。并查集的使用方法和此处一样。题解POJ 1456 Supermarket。
7、POJ 1733 Parity game
类似食物链那个题。题解POJ 1733 Parity game。
8、HDU 3038 How Many Answers Are Wrong
类似食物链那题。题解HDU 3038 How Many Answers Are Wrong。
9、POJ 1417 True Liars
并查集+DP。并查集的部分类似于食物链,后面的DP部分也很明显。总的来说思维难度比以上题略大,编码复杂度比较高。POJ 1417 True Liars
10、POJ 2912 Rochambeau
并查集的使用方法和食物链那题很像,但是还添加了其他东西,思维难度和编码复杂度均比较大。POJ 2912 Rochambeau
11、ZOJ 3261 Connections in Galaxy War
很巧妙的处理方法。如果不说是并查集的题应该会很难联想到并查集。就算联想到了,也是想出来这题的觉得很简单,没想出来的觉得很难。巧。ZOJ 3261 Connections in Galaxy War