简介
种类并查集:
和基础并查集有很大一部分相同, 多了一个判断2个元素是否属于同一个集团(不是集合, 集合是用来判断2个元素是否能够判断他们属不属于同一个集团:有点绕, 举个例子, 假如知道1和2在不同的集团, 3和4在不同集团,我们就不能判断1和3是否属于一个集团,而集团是用来判断他们是否在同一个集团假如:已知1和2在不同集团,2和3在不同集团, 那么我们就知道1和3在同一个集团);
要懂种类并查集就必须知道基础并查集:http://blog.csdn.net/fkjslee/article/details/48809903
特色
种类并查集多了一个集团, 我习惯用group[i]来代表i属于哪个集团;注意:group[i]代表的是他和pa[i]的关系, 并不是最后加入所有元素后i属于哪个集团;
举个例子:我们用0代表group[i]和group[pa[i] 属于同一个集团, 1代表不同;
现在有pa[3] = 4; group[3] = 1; 这里的group[3]仅仅代表3和4属于属于不同的集团!!!!!(非常重要, 不理解这点你会不能理解种类并查集的!!!), 至于最后3 在哪个集团会在find函数中更新, 下面我会用图示介绍;
同样分成种类并查集也分成两个:find 和union_set;
因为不同的种类并查集有一定差异:现在用一个例题来说明:POJ1182 http://poj.org/problem?id=1182
做法:每次找x和y是不是在同一个集合中:
如果是, 判断一下x和y满不满足它所给的关系。
如果不是, 说明这句话肯定为真:因为另一个集合中的所有元素可以一起变使得它满足x和y的关系; 同时合并两个集合;
当然这么说很简单, 具体做法及解释在下面:
最开始初始化pa[i] = i; group[i] = 0;
find函数:
不同的种类并查集有不同的find函数, 不过一般是这样:
下面代码中:
x 指的是需要查找的数;group[x]指的是x和他的父节点(pa[x])的关系:本题中
如果group[x] = 0代表x和pa[x]属于同一个物种,
如果group[x] = 1代表x吃pa[x],
如果group[x] = 2代表x被pa[x]吃;(当然不同的题这里可能不同)fa代表的是这个集合的根节点;
种类并查集的精华1:
每次find的时候更新它属于哪个group, 因为他之前的父亲的父亲已经是根节点了, 所以可以利用它之前的父亲和它和之前父亲的关系更新它和根节点的关系,当然更新后的group还是和父亲的关系; 不过父亲已经变成了根节点了;find的代码:
int find(int x) {
if(pa[