题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
解题思路:1.先求强连通分支,然后把图缩小成为一个有向无环图;
2.求出这个有向无环图中,入度为0的点的个数为a,出度为0的点的个数为b;
3.第一个问题的答案就是a,第二个问题的答案为max{a,b};
4.最恶心的地方:当一开始这个图就是一个强连通图的时候,第二问题的答案为0。
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=200 ;
const int M=10010 ;
struct node
{
int u,v,next ;
}e1[M] ;
struct node1
{
int u,v,next;
}e2[M] ;
int head1[N],head2[N],dfn[N],low[N],belong[N],stack[N],vist[N],in[N],out[N] ;
int top1,top2,sum,cnt,dep;
void add1(int u , int v)
{
e1[top1].u=u;
e1[top1].v=v;
e1[top1].next=head1[u] ;
head1[u]=top1++;
}
void add2(int u , int v)
{
e2[top2].u=u;
e2[top2].v=v;
e2[top2].next=head2[u] ;
head2[u]=top2++;
}
void tarjan(int u)
{
low[u]=dfn[u]=++dep;
stack[cnt++]=u;
vist[u]=1;
for(int i = head1[u] ; i!= -1 ; i=e1[i].next)
{
int v=e1[i].v ;
if(!dfn[v])
{
tarjan(v) ;
low[u] = min( low[u] , low[v]) ;
}
else if(vist[v])
low[u] = min( low[u] , dfn[v] ) ;
}
if(dfn[u] == low[u])
{ int x;
sum++;
do
{
x = stack[--cnt];
vist[x]=0;
belong[x]=sum;
}while(x != u) ;
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(head1,-1,sizeof(head1));
memset(head2,-1,sizeof(head2));
memset(belong,0,sizeof(belong)) ;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out)) ;
top1=top2=0;
for(int i = 1 ; i <= n ; i++)
{
int to ;
scanf("%d",&to) ;
while(to)
{
add1(i,to) ;
scanf("%d",&to) ;
}
}
memset(vist,0,sizeof(vist));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
cnt=dep=sum=0;
for(int i = 1 ; i <= n ; i++)
if(!dfn[i])
tarjan(i) ;
for(int i = 1 ; i <= n ; i++)
for(int j = head1[i] ; j!=-1 ; j=e1[j].next)
{
int v = e1[j].v ;
if(belong[i] != belong[v])
{ // printf("**");
add2(belong[i],belong[v]) ;
}
}
for(int i = 1 ; i <= sum ; i++)
for(int j = head2[i] ; j!=-1 ; j=e2[j].next)
{
int v = e2[j].v ;
in[v]++;
out[i]++;
}
int a=0,b=0; // printf("%d ",sum );
for(int i = 1 ; i <= sum ; i++)
{
if(in[i] == 0 )
a++ ;
if(out[i] == 0 )
b++ ;
}
if(sum <= 1 )
{
printf("1\n");
printf("0\n") ;
}
else
{
printf("%d\n",a);
printf("%d\n",max(a,b)) ;
}
}
return 0 ;
}