今天听队友讲课讲了并查集,好像比去年听的时候更明白了一些。同时,知道了除了普通并查集,还有种类并查集和带权并查集等。对于种类并查集的建模能力还有待提高,带权并查集可能又得下一个阶段才能学习了。
三个重要函数
void Init(int n){ //初始化
for(int i = 1; i <= n; i++)
f[i] = i;
}
int Find(int x){ //查询
return x == f[x] ? x : f[x] = Find(f[x]);
}
void Union(int x, int y){ //合并
int fx = Find(x);
int fy = Find(y);
if(fx != fy)//合并可按照树的高度来优化,暂且不表。
f[fy] = fx;
}
强调!!由于并查集的题往往数据范围较大,且Find()函数递归调用。故不宜使用cin,而应直接使用scanf.
No.1
HDU 1213 How Many Talbes
并查集模板题,套板子即可。
No.2
HDU 1272 小希的迷宫
判断是否是一个集合,且没有环
题解:在合并时如果x, y的根结点相等,说明存在环。在最后遍历一遍,若i == f[i]的个数大于1, 说明不止一个集合。
No.3
HDU 1232 畅通工程
并查集模板题,套板子即可。
No.4
HDU 1856 More is better
在普通并查集的基础上,求合并次数最多项。
题解:另设一t数组,初始都为1。每次合并时,若使f[fy] = fx;则t[fx] += t[fy];
No.5
POJ 1611 病毒传染
在普通并查集的基础上,要求每次合并时都以root为根节点。使用Union(root, x)即可。
No.6
POJ 2524 Ubiquitous Religions
并查集模板题,套板子即可。
带权并查集
带权并查集的特点是每个结点还保存着一定的信息,如到跟结点的距离,转移次数等。解决此类问题,就另设保存信息的数组,在每次转移时,信息也随之转移。注意,要先递归,再转移信息。遇到矛盾冲突问题,解决的关键是找到矛盾点,可通过画向量找关系式来解决。
No.7
HDU 3047 Zjnu Stadium
带权并查集
寻找座位安排的矛盾,转化成每个点到根结点的距离问题。带权并查集模板题。
No.8
HDU 3172 Virtual Friends
带权并查集+map
将所给字符串先对应转换成数字,再用并查集模板,同时需另设一数组t,表示转移次数。
No.9
HDU 3635 Dragon Balls
带权并查集
每个龙珠属于一个城市,当城市之间转移时,该城市所有龙珠都需转移。查询龙珠所在城市,该城市龙珠个数,以及转移次数。
题解:在普通并查集的基础上,另设一数组t,表示转移次数,在合并时自增。另设一数组num,表示每座城市龙珠数量,在合并时将孩子的龙珠数量增加过来。父亲的转移次数,需在Find()时加上孩子的转移次数。
注意!!!Find()中,先递归循环,再t[x] += t[f[x]];否则会产生时序错误。
种类并查集
种类并查集在使用三个函数时,无需变化。开数组时,有几种,就开几倍,在初始化时,参数也应为k * n。
在合并时,若为同种,则合并(x,y), (x + n, y + n), … ,(x + k * n, y + k * n);
若为异种,则合并(x, y + n), (x + n, y + 2 * n), … , (x + k * n, y)
在查询时,则指查询一种即可(由于合并时已同步操作)。
No.10
HDU 1829 A Bug’s Life
种类并查集
需要自己建模,抽象出为两种,接着套用种类并查集的模板。
No.11
POJ 1703 Find them, Catch them
种类并查集,犯人分为两个监狱,查询两人是否在同一监狱,抽象出种类有两种,接着套用板子。
No.12
POJ 1182 食物链
种类并查集经典题,A吃B,B吃C,C吃A,三种关系,种类有三种,接着套用板子。