题目大意:有N个学校,从每个学校都能从一个单向网络到另外一个学校,两个问题
1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。
2:至少需要添加几条边,使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。(就是最少加入几条边,让这个图变成强连通图)
解题思路:
首先找连通分量,然后看连通分量的入度为0点的总数,出度为0点的总数,那么问要向多少学校发放软件,就是入度为零的个数,这样才能保证所有点能够找到
然后第二问添加多少条边可以得到使整个图达到一个强连通分量,答案是入度为0的个数和出度为0的个数中最大的
但是当连通分量为1的时候,就直接输入1,0,因为如果Bcnt==1的时候这个图就是一个强连通图了就不需要加边了。
主要就是tarjan算法了,这个算法的注释可以看(点这里)
/*
Sample Input
5
2 4 3 0
4 5 0
0
0
1 0
Sample Output
1
2
*/
#include<stdio.h>
#include<vector>
#include<stack>
#include<string.h>
using namespace std;
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
int in[105];
int out[105];
int dfn[105];
int low[105];
int Belong[105];
int time=0,Bcnt=0;
bool in_S[105];
int n;
vector<int>e[105];
stack<int>S;
void tarjan(int u)
{
int i,v;
S.push(u);
in_S[u]=true;
dfn[u]=low[u]=++time;
for(i=0;i<e[u].size();i++)
{
v=e[u][i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(in_S[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
Bcnt++;
do{
v=S.top();
S.pop();
in_S[v]=false;
Belong[v]=Bcnt;
}while(v!=u);
}
}
int main()
{
int i,j,v;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
while(scanf("%d",&v)&&v)
{
e[i].push_back(v);
}
}
for(i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
if(Bcnt==1)
{
printf("1\n0\n");
return 0;
}
for(i=1;i<=n;i++)
for(j=0;j<e[i].size();j++)
{
v=e[i][j];
if(Belong[i]!=Belong[v])
{
in[Belong[v]]++;
out[Belong[i]]++;
}
}
int num=0,num1=0;
for(i=1;i<=Bcnt;i++)
{
if(in[i]==0)
num++;
if(out[i]==0)
num1++;
}
printf("%d\n%d\n",num,max(num,num1));
return 0;
}