首先应该求出来连通分量,进行缩点,然后求每个分量的入度和出度,入度等于0的很明显都需要分发一个文件,至于需要添加几条边可以成为一个强连通,就是出度和入度最大的那个,因为需要把出度和入度相连。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstring>
#include <algorithm>
#include <stack>
#include <vector>
using namespace std;
#define maxn 105
int head[maxn],cnt;
struct edge
{
int v,next;
}e[maxn*maxn];
int sta[maxn],instack[maxn],dfn[maxn];//sta数组模拟栈 instack数组表示是否在栈中 ;
int top,index,low[maxn],belong[maxn],bnt;
void add(int u, int v)
{
e[cnt].v=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
void tarjan(int k)
{
dfn[k]=low[k]=++index;
instack[k]=1;
sta[++top]=k;
int j;
for(j=head[k];j!=-1;j=e[j].next)
{
int v=e[j].v;
if(!dfn[v])
{
tarjan(v);
low[k]=min(low[k],low[v]);
}
else if(instack[v])
{
low[k]=min(low[k],dfn[v]);
}
}
if(dfn[k]==low[k])
{
++bnt;
do
{
j=sta[top--];
instack[j]=0;
belong[j]=bnt;
}while(k!=j);
}
}
void Init(int n)
{
cnt=bnt=index=top=0;
for(int i=1;i<=n;i++)
{
head[i]=-1;
dfn[i]=0;
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
int u,v;
Init(n);
for(int i=1;i<=n;i++)
{
while(scanf("%d",&v),v)
{
add(i,v);
}
}
for(int i=1;i<=n;i++)//
if(!(dfn[i]))
tarjan(i);
int r[maxn]={0},c[maxn]={0},rn=0,cn=0;
for(int i=1;i<=n;i++)
{
for(int j=head[i];j!=-1;j=e[j].next)
{
u=belong[i],v=belong[e[j].v];//u是v的父亲,所以u的出度+1,v的入度+1
if(u!=v)
{
c[u]++;
r[v]++;
}
}
}
for(int i=1;i<=bnt;i++)
{
if(r[i]==0)
rn++;
if(c[i]==0)
cn++;
}
if(bnt==1)
printf("1
0
");
else
printf("%d
%d
",rn,max(rn,cn));
}
return 0;
}