通过find函数找出该节点的根节点,
通过UNION函数将两棵树合并。
加入rank[N]来记录每个节点的秩(即树的高度),并按秩进行合并,可避免合并时的最糟糕情况,(树形为一条直线)
通过UNION函数将两棵树合并。
加入rank[N]来记录每个节点的秩(即树的高度),并按秩进行合并,可避免合并时的最糟糕情况,(树形为一条直线)
通过路径压缩可以减少每次寻找根节点的次数。
下面通过HDU1232(畅通工程)来进行分析:
Code
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int SIZE = 1005;
int root[SIZE];
int ranks[SIZE];
int find(int x)//查找并且路径压缩(非递归的路径压缩)
{
int y = x;
while (root[y] != y) {
y = root[y];
}
int temp, head = y;
y = x;
while (root[y] != y) {
temp = root[y];
root[y] = head;
y = temp;
}
return head;
};
void UNION(int x, int y)//按秩合并
{
int f1 = find(x);
int f2 = find(y);
if (ranks[f1] <= ranks[f2]) {
root[f1] = f2;
if (ranks[f1] == ranks[f2]) {
ranks[f2] ++;
}
} else {
root[f2] = f1;
}
};
int main()
{
int N, M, s, e, count;
while (scanf("%d%d",&N,&M)!=EOF, N) {
for (int i = 1; i <= N; ++ i)
root[i] = i,ranks[i] = 1;
//memset(ranks,1,sizeof(ranks));
for (int i = 0; i < M; ++ i) {
scanf("%d%d",&s,&e);
UNION(s,e);
}
count = -1;
for (int i = 1; i <= N; ++ i) {
if (root[i] == i)
++ count;
}
printf("%d\n",count);
}
}