反思:做题的时候一定要把算法理解清楚。
并查集模板讲解:
1.查询根的同时路径压缩,把a所在树的根作为a的父节点,而求所在树的根的时候,用
get_par(par[a])
语句不断向上寻找,直到找到根。根节点的par是它本身。
int get_par(int a)
{
if (par[a] != a) par[a] = get_par(par[a]);
return par[a];
}
2.查询两个点是否在同一个集合。如果两个点在同一棵树上,也就是根节点相同时,就在一个集合,查询的同时路径压缩了。
int query(int a, int b)
{
return get_par(a) == get_par(b);
}
3.合并集合操作。把a的根节点挂在b的根节点下面,把b的根节点作为a的par
void Merge(int a, int b)
{
par[get_par(a)] = get_par(b);
}
并查集的模板总共就这三个函数,最后一个比较重要的就是初始化。把所有节点的par设置为自己,因为最开始没有合并集合的时候,每个节点所在树只有自己,par当然也就是自己了。
for (int i = 1; i <= n; i++) {
par[i] = i;
}
题目完整代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
using namespace std;
const int maxn = 1010;
int n, m;
int par[maxn];
int get_par(int a)
{
if (par[a] != a) par[a] = get_par(par[a]);
return par[a];
}
int query(int a, int b)
{
return get_par(a) == get_par(b);
}
void Merge(int a, int b)
{
par[get_par(a)] = get_par(b);
}
void Init()
{
for (int i = 1; i <= n; i++) {
par[i] = i;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen ("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
int t;
scanf ("%d", &t);
while (t--) {
scanf ("%d%d", &n, &m);
Init ();
for (int i = 0; i < m; i++) {
int a, b;
scanf ("%d%d", &a, &b);
Merge (a, b);
}
int num = 0;
for (int i = 1; i <= n; i++) {
if (i == get_par(i)) {
num++;
}
}
printf ("%d\n", num);
}
}