先做一次裸tarjan,题目的思想主要是: 把一个SCC(强连通)看作一个点(缩点), 我们统计一下,每个SCC 的 入度和出度,因而再统计入度为零和出度为零的个数。 最后的两个答案, 是 入度为零的个数 和 max(入度为零,出度为零)。
import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Scanner;
import java.util.Stack;
public class poj1236{
static int[]in,belong,out,ins,head,low,dfn;
static int n,m,con,ans,cnt,time;
static Stack<Integer> s;
static class e{
int u,v;int next;
}static e[]es;
static void add(int u,int v) {
if(es[con]==null) es[con]=new e();
es[con].v=v; es[con].next=head[u];head[u]=con++;
}
static void tarjan(int u) {
s.add(u); ins[u]=1; dfn[u]=low[u]=++time;
for(int i=head[u];i!=-1; i=es[i].next) {
int v= es[i].v;
if(dfn[v]==0) { tarjan(v); low[u]= Math.min(low[v] ,low[u]); }
else if(ins[v]==1) low[u]= Math.min(dfn[v], low[u]);
}
if(dfn[u]==low[u]) {
ans++;
int j = -1;
while(j!=u && !s.isEmpty()) {
j=s.pop(); ins[j]=0; belong[j]=ans;
}
}
}
public static void main(String[] args) {
Scanner sc= new Scanner(new BufferedInputStream(System.in));
es=new e[10005];
head=new int[ 10005];
low=new int[200];
dfn=new int[200];
belong=new int[200];
ins =new int[200];
in=new int[200];
out=new int[200];
s=new Stack<Integer>(); s.clear();
Arrays.fill(head,-1); con=0; time=0;ans=0;
Arrays.fill(dfn,0);
Arrays.fill(ins,0);
Arrays.fill(in,0);
Arrays.fill(out,0);
Arrays.fill(low,0);
Arrays.fill(belong,0);
int m =sc.nextInt();
for(int i=1;i<=m;i++) {
while(sc.hasNext()) {
int a=sc.nextInt();
if(a==0) break;
else {
add(i,a);
}
}
}
for(int i=1;i<=m;i++) {
if(dfn[i]==0) {
tarjan(i);
}
}
for(int i=1;i<=m;i++) {
for(int j=head[i]; j!=-1; j=es[j].next) {
int v =es[j].v;
if(belong[i]!=belong[v]) {
out[belong[i]]++;
in[belong[v]]++;
}
}
}
int outnum=0,innum=0; //出度为零的Scc 的数量 , 入度为零的scc的数量
for(int i=1;i<=ans;i++) {
if(in[i]==0) innum++;
if(out[i]==0)outnum++;
}
System.out.println( innum);
if(ans==1)System.out.println( 0);
else System.out.println(Math.max( innum,outnum));
}
}