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; }