并查集是一个简单而又有效的算法,代码实现起来也挺简单的。。。。
基本的实现代码如下面所示,不明白的可以参考链接https://blog.csdn.net/niushuai666/article/details/6662911
直接用代码解释吧。。。
用hdu1232解释吧。
void init(int x) //初始化,相当于一开始每个城市一个整体,没有道路跟它相连
{
for(int i = 1; i <= x; i++)
pre[i] = i;
}
int unite(int root) //假定一个城市是个首都,周围的城市向他靠拢,也就是建路
{
int son, tmp;
son = root;
while(root != pre[root]) //寻找首都
root = pre[root];
while(son != root) //路径压缩
{
tmp = pre[son];
pre[son] = root;
son = tmp;
}
return root;
}
void join(int root1, int root2)
{
root1 = unite(root1); //寻找它的首都
root2 = unite(root2);
if(root1 != root2) 如果不连通,就把它们所在的连通分支合并
pre[root1] = root2; //这一步有个可以优化的点,就是把小的一方的分支并到大的一方,但在网上给的代码上好像很少有人弄,可能是退化的可能性不高吧
}
给一波需要考虑树的规模大小的代码(白书)
void init(int n)
{
for(int i = 0; i < n; i++)
{
per[i] = i;
rank[i] = 0;
}
}
int find(int x)
{
if(per[x] == x)
return x;
else
return per[x] = find(per[x]);
}
void unite(int x, int y)
{
x = find(x);
y = find(y);
if(x == y)
return;
if(rank[x] < rank[y])
per[x] = y;
else
{
per[y] = x;
if(rank[x] == rank[y])
rank[x]++;
}
}
顺便附上hdu1232题目的代码
#include <cstdio>
using namespace std;
int pre[1005];
int n, m, total, st, en, root1, root2;
void init(int x) //初始化
{
for(int i = 1; i <= x; i++)
pre[i] = i;
}
int unite(int root)
{
int son, tmp;
son = root;
while(root != pre[root]) //寻找最后的boss
root = pre[root];
while(son != root) //路径压缩
{
tmp = pre[son];
pre[son] = root;
son = tmp;
}
return root;
}
int main()
{
while(~scanf("%d %d", &n, &m) && n)
{
total = n - 1;
init(n);
while(m--)
{
scanf("%d %d", &st, &en);
root1 = unite(st);
root2 = unite(en);
if(root1 != root2)
{
pre[root1] = root2;
total--;
}
}
printf("%d\n", total);
}
return 0;
}