P3420 [POI2005]SKA-Piggy Banks
题面
Byteazar the Dragon拥有N个小猪存钱罐。每一个存钱罐能够用相应的钥匙打开或者被砸开。Byteazar已经将钥匙放入到一些存钱罐中。现在已知每个钥匙所在的存钱罐,Byteazar想要买一辆小汽车,而且需要打开所有的存钱罐。然而,他想要破坏尽量少的存钱罐,帮助Byteazar去决策最少要破坏多少存钱罐。
任务:
写一段程序包括:
读入存钱罐的数量以及相应的钥匙的位置,求出能打开所有存钱罐的情况下,需要破坏的存钱罐的最少数量并将其输出。
思路
判断环,有环就砸。
做法
并查集,出来吧!
伪代码如下:
for i:1->n
begin
if(Find(x)=i)
begin
fa[i]=i
ans++;
end
else
begin
fa[i]=x
end
end
实际代码如下
#include<bits/stdc++.h>
using namespace std;
// size:大小 compress:路径压缩 merge_rank:按秩合并
template<int size=2500,bool compress=true,bool merge_rank=true>
class UnionFindSet{
private:
int fa[size+1];
int rank[size+1];
public:
UnionFindSet(){
for(int i=0;i<size;i++){
this->fa[i]=i;
if(merge_rank){
this->rank[i]=1;
}
}
}
int find(int x){
if(!compress){
if(this->fa[x]==x){
return x;
}
else{
return this->find(this->fa[x]);
}
}
else{
if(x==this->fa[x]){
return x;
}
else{
this->fa[x]=this->find(this->fa[x]);
return fa[x];
}
}
}
void merge(int x,int y){
if(!merge_rank){
this->fa[this->find(x)]=find(y);
}
else{
int a=this->find(x);
int b=this->find(y);
if(this->rank[a]<=this->rank[b]){
this->fa[a]=b;
}
else{
this->fa[b]=a;
}
if(rank[a]==rank[b]&&a!=b){
rank[b]++;
}
}
}
bool same(int x,int y){
return this->find(x)==this->find(y);
}
void _fa_setValue(int i,int x){
this->fa[i]=x;
}
int _fa_getValue(int i){
return this->fa[i];
}
void _rank_setValue(int i,int x){
this->rank[i]=x;
}
int _rank_getValue(int i){
return this->rank[i];
}
};
int n,ans=0;
UnionFindSet<1000005,true,true> uf;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
if(uf.find(x)==i){
uf._fa_setValue(i,i);
ans++;
}
else{
uf._fa_setValue(i,x);
}
}
cout<<ans;
return 0;
}