並查集是一個簡單而又有效的算法,代碼實現起來也挺簡單的。。。。
基本的實現代碼如下面所示,不明白的可以參考鏈接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;
}