写个并查集的博客,我选择用江湖门派来解释并查集程序(之前看过一个博客也是用江湖门派来解释,很通俗易懂),并查集主要分为两个步骤:寻找根节点和路径压缩。假设每个元素都是一名侠客,那么寻找根节点就是寻找掌门的过程,路径压缩就是门派合并的过程。这篇博客重在如何巧妙的理解和记忆并查集的过程,所以没有具体解释寻找根节点和路径压缩的详细过程,读者可以先大致了解一下寻找根节点和路径压缩的具体过程再来与这篇博客进行对比,这样就很容易理解并查集了。
#include<bits/stdc++.h>
using namespace std;
int pre[1000]; //该数组存储每一名侠客,每名侠客都有自己的编号
int find(int x) { //找掌门
if (x == pre[x]) return x; //如果x的掌门是自己,则返回自己
return find(pre[x]); //如果x的掌门不是自己,就让x的上级继续找
}
void join(int x, int y) { //周芷若和虚竹想做朋友,但他们不是一个门派,那就把这两个门派合并成一个
int fx = find(x); //找到周芷若的掌门
int fy = find(y); //找到虚竹的掌门
if (fx != fy) //如果两个人的掌门不是同一个人
pre[fx] = fy; //那就让周芷若的掌门当虚竹掌门的上级,两个门派合并成功
}
int main() {
int N, M, x, y;
bool t[1000];
while (cin >> N && N != 0) {
cin >> M;
int count = 0;
for (int i = 1; i <= N; i++) //初始化数组,每一个测试用例都要初始化数组
pre[i] = i;
for (int i = 1; i <= M; i++) {
cin >> x >> y;
join(x, y);
}
memset(t, 0, sizeof(t));
for (int i = 1; i <= N; i++) {
t[find(i)] = 1;
}
for (int i = 1; i <= N; i++) {
if (t[i] == 1)
count++;
}
cout << count - 1 << endl;
}
}