毫无理由地献上证明:(其实就是Tarjan缩点以后做)
https://blog.csdn.net/tomandjake_/article/details/81842963
#include<iostream>
#include<string.h>
#define N 150
using namespace std;
int dfn[N],low[N],id[N],a[N][N],n,past[N],pl,cnt,sum;
bool vis[N],pre[N],suf[N];
void tarjan(int x)
{
dfn[x]=low[x]=++sum;
past[++pl]=x;
for (int i=1;i<=n;i++)
if (!vis[i]&&a[x][i]>0){
if (low[i]==0x3f3f3f3f)tarjan(i);
low[x]=(low[x]<low[i])?low[x]:low[i];
}
if (low[x]==dfn[x]){
++cnt;
do{
int now=past[pl];
id[now]=cnt;
} while (past[pl--]!=x);
}
vis[x]=true;
}
void trans()
{
memset(pre,false,sizeof(pre));memset(suf,false,sizeof(suf));
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (id[i]!=id[j]&&a[i][j])pre[id[j]]=true,suf[id[i]]=true;
}
int main()
{
cin>>n;
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++){
int v;
while (true){
cin>>v;
if (v==0)break;
a[i][v]=1;
}
}
memset(dfn,0,sizeof(dfn));memset(low,0x3f,sizeof(low));memset(vis,false,sizeof(vis));
cnt=0,sum=0;pl=0;
for (int i=1;i<=n;i++)
if (!vis[i])tarjan(i);
if (cnt==1){cout<<"1\n0\n";return 0;}
trans();
int sum1=0,sum2=0;
for (int i=1;i<=cnt;i++){
if (!pre[i])sum1++;
if (!suf[i])sum2++;
}
cout<<sum1<<"\n"<<((sum1>sum2)?sum1:sum2)<<"\n";
return 0;
}
原文:https://www.cnblogs.com/live-no-regrets/p/14053942.html