题目描述
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 }