题目:https://www.luogu.org/problemnew/show/P2746
AC代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MaxN=1e2+5,MaxM=1e4+5;
int n,x,ans1,ans2;
inline int get(){//读入优化
char c=getchar();
int x=0;
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
return x;
}
int tot,nex[MaxM],from[MaxM],to[MaxM],head[MaxN];
void join(int x,int y){
nex[++tot]=head[x];
from[tot]=x;
to[tot]=y;
head[x]=tot;
}
int num,dfn[MaxN],low[MaxN],st[MaxN],top,col,co[MaxN],si[MaxN];
void Tarjan(int u){//求SCC
dfn[u]=low[u]=++num;
st[++top]=u;
for(int i=head[u];i;i=nex[i]){
int v=to[i];
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!co[v])low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){//不在上面的for里面!!
co[u]=++col;
++si[col];
while(st[top]!=u){
co[st[top]]=col;
++si[col];
--top;
}
--top;
}
}
int cd[MaxN],rd[MaxN];
void ReBuild(){//求新图中新点的出度入度
for(int i=1;i<=tot;i++){
int u=from[i],v=to[i];
if(co[u]!=co[v]){
cd[co[u]]++;
rd[co[v]]++;
}
}
}
int main(){
n=get();
for(int i=1;i<=n;i++)
while(1) {
x=get();
if(!x)break;
join(i,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i])Tarjan(i);
ReBuild();
for(int i=1;i<=col;i++){
if(rd[i]==0)ans1++;
if(cd[i]==0)ans2++;
}
//出度为0的点指向入度为0的点连边,构成回路
if(col!=1)cout<<ans1<<endl<<max(ans1,ans2);
else cout<<1<<endl<<0;//特判
return 0;
}