洛谷 P3420 [POI2005]SKA-Piggy Banks 题解
蒟蒻的第二篇题解
嗯,直接进入正题
先告诉你们这是并查集,好吧,标签上面有,再来分析这为什么是并查集。
根据题意:
每一个存钱罐能够用相应的钥匙打开或者被砸开,Byteazar已经将钥匙放入到一些存钱罐中
我们可以理解成:
如果这是一个联通块的“祖先”(也可以称为根吧,蒟蒻不知道该怎么称呼)那么就把它砸破,这样整个联通块就都可以取出;
如果不是的话,就不管它;
从后面句话就可以很明显的推出他们之间有从属关系(如果要砸的数目最小),这是并查集的思想,是吧;
好,既然我们已经知道了它要用并查集做;
那么,就是一个模板呀,上模板就可以了,最后输出联通块的个数;
OK,上代码,代码中也有注释:
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000010
int n, ans, x, fa[maxn];
/*
//三目运算符版本
int find(int x)
{
return fa[x] == x ? x : fa[x] = find(fa[x)'
}
*/
//普通的呐
int find(int x)
{
if(fa[x] == x)
return x;
return fa[x] = find(fa[x]);
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++ i)
fa[i] = i;//最开始,每个人都是自己的祖先;
for(int i = 1; i <= n; ++ i)
{
scanf("%d", &x);
fa[find(i)] /*找祖先*/ = find(x)/*找它的儿子的祖先*/;
//就是合并两个集合呐
}
for(int i = 1; i <= n; ++ i)
if(fa[i] == i)//求联通块的个数
++ ans;
printf("%d", ans);
return 0;
}