并查集aoj夺宝奇兵

HF市地下有一份宝藏,数不清的黄金、钻石……。令人遗憾的是,千年来未曾有人得到过这份宝藏。其中一个主要原因就是,要得到这份宝藏之前,首先需要通过一个迷宫。

这个迷宫的结构非常复杂,一共有N个秘密房间。广为流传的一种说法是,必须在1天之内将这N个房间的门全部打开,才能找到迷宫的出口,否则就会葬身于其中。传说中同时

指出,这些房间之间有着错综复杂的联系。对于每个房间而言,仅有一把能够打开这个房间的钥匙,这把钥匙可能位于这N个房间中的任意一个。每当一个房间被打开后,就可

以得到房间里面的钥匙,并以打开其他的房间。被世人称为有史以来最天才的探险家小雪准备于近日进入迷宫探险。为了确保万无一失,他携带了足量的新型炸弹,每枚炸弹可

以将一个房间的门直接炸掉。由于炸弹的威力太大,可能破坏整个迷宫的结果,小雪准备用最少的炸弹打开所有的房间,你能够帮助小雪计算一下吗?



Input

第一行包含一个整数N(N<=1000000),表示迷宫中房间的数目。接下来的N行,每行包含一个整数,表示能够打开第i个房间的钥匙的位置。



Output

仅包含一个整数,表示最少需要的炸弹的数目。



Sample Input

Original Transformed


4

2

1

2

4


Sample Output

Original Transformed


2

分析:此处每个房间是独立的,即1号房间与2号不是相邻的,可以选择先进1号房间或其他房间,没顺序约束。此时,题目即转化为简单的并查集,即输入的整数a与房间序号i是连通的,虽然看似只能依序才能进入房间,但不会影响每个房间链(即连通图)最少只要一颗炸弹,所以其实只需计算独立的连通图的个数即可。(具体格式介绍见连通图)

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 1000010;

int p[maxn];
int sum;

int Find(int x){//查找
    return p[x] == x ? x : p[x] = Find(p[x]);
}

void Union(int x, int y){//合并
    int x_root = Find(x);
    int y_root = Find(y);
    if(x_root != y_root){
        p[x_root] = y_root;
        sum--;//成功的合并,总体未连通点的数目减1
    }
}


int main(){
    int a, n;
    scanf("%d", &n);
    sum = n;
    for(int i = 1; i <= n; i++) p[i] = i;//初始化
    for(int i = 1; i <= n; i++){
        scanf("%d", &a);
        Union(a, i);//合并
    }
    printf("%d\n", sum);
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值