满分做法:
子任务A的答案应为缩点之后,入度为\(0\)的个数。子任务B的答案为入度和出度为\(0\)个数的最大值。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxm=2e4+7;
int pre[maxm],last[maxm],dfn[maxm],low[maxm],other[maxm],l;
bool vis[maxm];
int sta[maxm],top=0,tot=0,size[maxm],id[maxm];
int n,from[maxm],ru[maxm],ans,chu[maxm],ans1,idd;
void add(int x,int y)
{
l++;
from[l]=x;
pre[l]=last[x];
last[x]=l;
other[l]=y;
}
void dfs(int x)
{
dfn[x]=low[x]=++tot;
vis[x]=1;
sta[++top]=x;
for(int p=last[x];p;p=pre[p])
{
int v=other[p];
if(!dfn[v])
{
dfs(v);
low[x]=min(low[x],low[v]);
}
else if(vis[v]) low[x]=min(low[x],dfn[v]);
}
if(dfn[x]==low[x])
{
int y=0;
idd++;
while(y!=x)
{
y=sta[top--];
vis[y]=0;
size[x]++;
id[y]=x;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
while(scanf("%d",&x))
{
if(x==0) break;
add(i,x);
}
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
dfs(i);
}
for(int i=1;i<=l;i++)
{
int x=id[from[i]],y=id[other[i]];
if(x!=y)
{
ru[y]++;
chu[x]++;
}
}
// cout<<id[1]<<" "<<id[2]<<" "<<id[5]<<endl;
for(int i=1;i<=n;i++)
{
if(!ru[i]&&low[i]==dfn[i])
ans++;
if(!chu[i]&&low[i]==dfn[i])
ans1++;
}
if(idd==1)
printf("1\n0\n");
else
printf("%d\n%d\n",ans,max(ans,ans1));
return 0;
}