[并查集]夺宝奇兵
题目描述
HF市地下有一份宝藏,数不清的黄金、钻石……。令人遗憾的是,千年来未曾有人得到过这份宝藏。其中一个主要原因就是,要得到这份宝藏之前,首先需要通过一个迷宫。
这个迷宫的结构非常复杂,一共有N个秘密房间。广为流传的一种说法是,必须在1天之内将这N个房间的门全部打开,才能找到迷宫的出口,否则就会葬身于其中。传说中同时
指出,这些房间之间有着错综复杂的联系。对于每个房间而言,仅有一把能够打开这个房间的钥匙,这把钥匙可能位于这N个房间中的任意一个。每当一个房间被打开后,就可
以得到房间里面的钥匙,并以打开其他的房间。被世人称为有史以来最天才的探险家小雪准备于近日进入迷宫探险。为了确保万无一失,他携带了足量的新型炸弹,每枚炸弹可
以将一个房间的门直接炸掉。由于炸弹的威力太大,可能破坏整个迷宫的结果,小雪准备用最少的炸弹打开所有的房间,你能够帮助小雪计算一下吗?
输入
第一行包含一个整数N(N<=1000000),表示迷宫中房间的数目。接下来的N行,每行包含一个整数,表示能够打开第i个房间的钥匙的位置。
输出
仅包含一个整数,表示最少需要的炸弹的数目。
样例输入
4
2
1
2
4
样例输出
2
这一题就是并查集的直接应用,有钥匙就可以直接进入,进入一个房间i的钥匙在j,先j后i,说明j是i的祖先,即使有回边的情况,由于必须先进入一个房间再取钥匙,炸弹就把这个回边炸没了,最后只要统计多少个根结点即可。事实上建边的顺序不影响结果。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<algorithm>
const int N = 1000005;
int fa[N];
int n;
int find(int x)//返回x的祖先
{
return fa[x] == x ? x : 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++) {//能打开第i个门的钥匙
int key;
scanf("%d", &key);
if (find(key) != find(i)) {
fa[i] = key;
}
}
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (fa[i] == i)cnt++;
}
printf("%d\n", cnt);
}