P3420 [POI2005]SKA-Piggy Banks

题目描述

Byteazar the Dragon拥有N个小猪存钱罐。每一个存钱罐能够用相应的钥匙打开或者被砸开。Byteazar已经将钥匙放入到一些存钱罐中。现在已知每个钥匙所在的存钱罐,Byteazar想要买一辆小汽车,而且需要打开所有的存钱罐。然而,他想要破坏尽量少的存钱罐,帮助Byteazar去决策最少要破坏多少存钱罐。

任务:

写一段程序包括:

读入存钱罐的数量以及相应的钥匙的位置,求出能打开所有存钱罐的情况下,需要破坏的存钱罐的最少数量并将其输出。

输入格式

第一行:包括一个整数N(1<=N<=1000000),这是Byteazar the Dragon拥有的存钱罐的数量。

存钱罐(包括它们对应的钥匙)从1到N编号。

接下来有N行:第i+1行包括一个整数x,表示第i个存钱罐对应的钥匙放置在了第x个存钱罐中。

输出格式

仅一行:包括一个整数,表示能打开所有存钱罐的情况下,需要破坏的存钱罐的最少数量。

 这道题是并查集的较为简单的应用。如果第i个存钱罐的钥匙存储在了第j个存钱罐内,则打开了第j个存钱罐,也就间接地打开了第i个存钱罐。因此,如果第i个存钱罐的钥匙存储在了第j个存钱罐内,则我们一定可以通过打开第j个存钱罐的方式,拿到第i个存钱罐的钥匙。这样,我们可以将其理解为i和j被放到了一个集合里。这样我们只需要统计一共有几个集合,即可求出需要破坏的存钱罐数量。

如何统计一共有几个集合?只需要在对father数组初始化时将集合数设为n,然后每进行一次合并操作将集合数减一即可。

代码:

 1 #include<iostream>
 2 using namespace std;
 3 int n,x,y;
 4 int fa[1000005];
 5 inline int find(const int &x){
 6     if(fa[x]==x){
 7         return x;
 8     }else{
 9         return fa[x]=find(fa[x]);
10     }
11 }
12 inline void unionn(const int &x,const int &y){
13     int r1=find(x);
14     int r2=find(y);
15     fa[r1]=r2;
16 }
17 int main(){
18     cin>>n;
19     int num=n;//n个集合
20     for(int i=1;i<=n;i++){
21         fa[i]=i;
22     }
23     for(int i=1;i<=n;i++){
24         cin>>x;
25         if(find(i)!=find(x)){
26             unionn(i,x);
27             num--;
28         }
29     }
30     cout<<num<<endl;
31     return 0;
32 }
原文地址:https://www.cnblogs.com/qianr/p/13380884.html