【BZOJ1529】[POI2005]ska Piggy banks
Description
Byteazar 有 N 个小猪存钱罐. 每个存钱罐只能用钥匙打开或者砸开. Byteazar 已经把每个存钱罐的钥匙放到了某些存钱罐里. Byteazar 现在想买一台汽车于是要把所有的钱都取出来. 他想尽量少的打破存钱罐取出所有的钱,问最少要打破多少个存钱罐.
Input
第一行一个整数 N (1 <= N <= 1.000.000) – 表示存钱罐的总数. 接下来每行一个整数,第 i+1行的整数代表第i个存钱罐的钥匙放置的存钱罐编号.
Output
一个整数表示最少打破多少个存钱罐.
Sample Input
4
2
1
2
4
2
1
2
4
Sample Output
2
In the foregoing example piggy banks 1 and 4 have to be smashed.
In the foregoing example piggy banks 1 and 4 have to be smashed.
题解:Tarjan缩点,答案就是入度为0的连通块的个数
#include <cstdio> #include <cstring> int tp,tot,n,ans,cnt,sum; int head[1000010],next[1000010]; int deep[1000010],low[1000010],sta[1000010],ins[1000010],vis[1000010],bel[1000010],d[1000010]; int min(int x,int y) { return x<y?x:y; } void tarjan(int x) { int i,t; deep[x]=low[x]=++tot; ins[x]=vis[x]=1; sta[++tp]=x; for(i=head[x];i;i=next[i]) { if(!vis[i]) { tarjan(i); low[x]=min(low[x],low[i]); } else if(ins[i]) low[x]=min(low[x],deep[i]); } if(deep[x]==low[x]) { ans++; do { t=sta[tp--]; bel[t]=ans; ins[t]=0; }while(t!=x); } } int main() { scanf("%d",&n); int i,j,a; for(i=1;i<=n;i++) { scanf("%d",&a); next[i]=head[a]; head[a]=i; } for(i=1;i<=n;i++) if(!vis[i]) tarjan(i); for(i=1;i<=n;i++) for(j=head[i];j;j=next[j]) if(bel[i]!=bel[j]) d[bel[j]]=1; for(i=1;i<=ans;i++) if(!d[i]) sum++; printf("%d",sum); return 0; }