题目传送门
\(Tarjan\)缩点,缩点后找入度为\(0\)的点的数量(第一问),第二问是取\(max(\)入度为\(0\)的点的数量,出度为\(0\)的点的数量\()\)
P.S.别忘了特判缩成一个点的情况
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct zzz{
int f,t,nex;
}e[10010<<1]; int head[110],tot;
void add(int x,int y){
e[++tot].f=x;
e[tot].t=y;
e[tot].nex=head[x];
head[x]=tot;
}
int read(){
int k=0; char c=getchar();
for(;c<'0'||c>'9';) c=getchar();
for(;c>='0'&&c<='9';c=getchar())
k=(k<<3)+(k<<1)+c-48;
return k;
}
int dfn[110],low[110],deth,s[110],top,belong[110],col;
bool vis[110];
void tarjan(int f){
dfn[f]=low[f]=++deth;
s[++top]=f,vis[f]=1;
for(int i=head[f];i;i=e[i].nex){
int to=e[i].t;
if(!dfn[to]){
tarjan(to);
low[f]=min(low[f],low[to]);
}
else
if(vis[to]) low[f]=min(low[f],dfn[to]);
}
if(dfn[f]==low[f]){
col++;
int k=0;
do{
k=s[top--];
belong[k]=col;
vis[k]=0;
}while(k!=f);
}
}
int in[110],out[110],innum,outnum;
int main(){
int n=read();
for(int i=1;i<=n;i++)
while(int k=read())
add(i,k);
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=tot;i++){
int x=e[i].f,y=e[i].t;
if(belong[x]!=belong[y])
in[belong[y]]++, out[belong[x]]++;
}
for(int i=1;i<=col;i++){
if(!in[i]) innum++;
if(!out[i]) outnum++;
}
printf("%d\n%d",innum,col==1? 0:max(innum,outnum));
return 0;
}