碰巧在学习kruskal算法来实现最小生成树,其中用到了并查集,然后详细研究了并查集。找到一篇好的链接。原文链接参考:https://blog.csdn.net/qq_41593380/article/details/81146850
具体并查集解释参考链接。代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int pre[1010]; //里面全是掌门
int unionsearch(int root)
{
int son, tmp;
son = root;
while(root != pre[root]) //寻找掌门ing……
root = pre[root];
while(son != root) //路径压缩
{
tmp = pre[son];
pre[son] = root;
son = tmp;
}
return root; //掌门驾到~
}
int main()
{
int num, road, total, i, start, end, root1, root2;
while(scanf("%d%d", &num, &road) && num)
{
total = num - 1; //共num-1个门派
for(i = 1; i <= num; ++i) //每条路都是掌门
pre[i] = i;
while(road--)
{
scanf("%d%d", &start, &end); //他俩要结拜
root1 = unionsearch(start);
root2 = unionsearch(end);
if(root1 != root2) //掌门不同?踢馆!~
{
pre[root1] = root2;
total--; //门派少一个,敌人(要建的路)就少一个
}
}
printf("%d\n", total);//天下局势:还剩几个门派
}
return 0;
}
代码重点应该在查找函数unionsearch(int root)以及合并函数(如下代码),当然这也是并查集含有的两项基本操作。main函数中代码写得有些啰嗦了,没仔细体会。这份代码固然逻辑清楚,代码简洁,但是还是有许多要改的地方。比如,在合并操作上,应该是将高度低的子树合并到高度高的子树,这样才能够保证合成树的高度尽可能低。从而能够满足高速查找操作。完美的并查集理论上是可以做到查找和合并都做到O(logn)的。
void join(int root1, int root2) //虚竹和周芷若做朋友
{
int x, y;
x = unionsearch(root1);//我老大是玄慈
y = unionsearch(root2);//我老大是灭绝
if(x != y)
pre[x] = y; //打一仗,谁赢就当对方老大
}