ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

Byteazar 有 N 个小猪存钱罐. 每个存钱罐只能用钥匙打开或者砸开. Byteazar 已经把每个存钱罐的钥匙放到了某些存钱罐里. Byteazar 现在想买一台汽车于是要把所有的钱都取出来. 他想尽量少的打破存钱罐取出所有的钱,问最少要打破多少个存钱罐. 

Input

第一行一个整数 N (1 <= N <= 1.000.000) – 表示存钱罐的总数. 接下来每行一个整数,第 i+1行的整数代表第i个存钱罐的钥匙放置的存钱罐编号. 

Output

一个整数表示最少打破多少个存钱罐.
由存钱罐向钥匙所在存钱罐连边得到基环内向森林
从a能到达b说明若打破b可以打开a
因此答案为环的个数,拓扑排序求一下即可
#include<cstdio>
char buf[10000005],*ptr=buf-1;
inline int input(){
    int x=0,c=*++ptr;
    while(c>57||c<48)c=*++ptr;
    while(c>47&&c<58)x=x*10+c-48,c=*++ptr;
    return x;
}
const int N=1000100;
int n;
int fa[N],q[N],in[N],ql=0,qr=0;
bool ed[N];
int main(){
    fread(buf,1,10000000,stdin);
    n=input();
    for(int i=1;i<=n;i++)++in[fa[i]=input()];
    for(int i=1;i<=n;i++)if(!in[i])q[qr++]=i;
    while(ql!=qr){
        int w=q[ql++];
        ed[w]=1;
        if(!--in[fa[w]])q[qr++]=fa[w];
    }
    int ans=0;
    for(int a=1;a<=n;a++)if(!ed[a]){
        int b=a;
        do{
            b=fa[b];
            ed[b]=1;
        }while(b!=a);
        ++ans;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted on 2016-05-21 16:52  nul  阅读(178)  评论(0编辑  收藏  举报