题目:http://www.sqyoj.club/problem.php?id=1018
分析:求出SCC后缩点,重新构图,统计新图中入度为0的点的个数即为答案。下面代码是用Kosaraju求SCC。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int num,head[201],fnum,fhead[201];
int n,x;
int vis[201],fvis[201];
int in[201],out[201];
int nd[201],cns,scc;
int belong[201];
int ans;
struct Edge{
int from,to,next;
};
Edge edge[80000],fedge[80000];
void join(int from,int to){
++num;
edge[num].from=from;
edge[num].to=to;
edge[num].next=head[from];
head[from]=num;
}
void fjoin(int from,int to){
++fnum;
fedge[fnum].from=from;
fedge[fnum].to=to;
fedge[fnum].next=fhead[from];
fhead[from]=fnum;
}
void dfs(int v){
for(int i=head[v];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(!vis[to]){
vis[to]=1;
dfs(to);
nd[++cns]=to;
}
}
}
void fdfs(int v){
for(int i=fhead[v];i!=-1;i=fedge[i].next){
int to=fedge[i].to;
if(!fvis[to]){
fvis[to]=1;
belong[to]=scc;
fdfs(to);
}
}
}
void buildgraph(){
for(int i=1;i<=n;i++){
for(int j=head[i];j!=-1;j=edge[j].next){
int to=edge[j].to;
if(belong[i]==belong[to])continue;
out[ belong[i] ]++;
in[ belong[to] ]++;
}
}
}
int main(){
memset(head,-1,sizeof(head));
memset(fhead,-1,sizeof(head));
cin>>n;
for(int i=1;i<=n;i++)
while(scanf("%d",&x) && x){
join(i,x);
fjoin(x,i);
}
/*Kosaraju*/
for(int i=1;i<=n;i++)
if(!vis[i]){
vis[i]=1;
dfs(i);
nd[++cns]=i;
}
for(int i=cns;i>=1;i--)
if(!fvis[ nd[i] ]){
fvis[ nd[i] ]=1;
scc++;
belong[ nd[i] ]=scc;
fdfs( nd[i] );
}
/*缩点构图*/
buildgraph();
for(int i=1;i<=scc;i++)if(in[i]==0)ans++;
cout<<ans;
return 0;
}