案例:
首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支。如果是1个连通分支,说明整幅图上的点都连起来了,不用再修路了;如果是2个连通分支,则只要再修1条路,从两个分支中各选一个点,把它们连起来,那么所有的点都是连起来的了;如果是3个连通分支,则只要再修两条路……
上述问题转化为并查集,即只需要计算有多少个集合。 并查集详解,参考:blog.csdn.net/liujian2015…
解决相关问题:等式方程的可满足性
并查集C++实现:
class unionFindSet {
vector<int> ufs;
public:
unionFindSet(int size) {
ufs.resize(size, -1);
// 初始化为-1,表示每个节点一个集合,每个集合的元素总数为1(-1的绝对值)
}
// 合并两个集合
void unionSet(int idx1, int idx2) {
// 首先找到两个集合各自的根节点
int root1 = findRoot(idx1);
int root2 = findRoot(idx2);
// 根节点相同,证明原本就属于一个集合,无需合并
if (root1 == root2) {
return;
}
// 若idx非集合根节点,则ufs[idx]表示其上级节点的索引(正值)
// 若idx为某一集合根节点,则ufs[idx]的绝对值表示该集合元素总数
// 合并两个集合,将两集合元素总数相加
// 合并后,root1为新集合的根节点,root2的上级节点为root1
ufs[root1] += ufs[root2];
ufs[root2] = root1;
}
// 查找idx所在集合的根节点
void findRoot(int idx) {
// ufs[idx] < 0, idx为根节点
// ufs[idx] > 0时,ufs[idx]表示当前节点的上级节点的索引,继续向上查找
while (ufs[idx] > 0) {
idx = ufs[idx];
}
return idx;
}
// 存在多少个集合,即ufs[idx] < 0 的值总数
int count() {
int count = 0;
for (int i = 0; i < ufs.size(); ++i) {
if (ufs[i] < 0) {
++count;
}
}
return count;
}
}