题意:学校有一些单向网络,现在需要传一些文件,1,求最少需要向几个学校分发文件才能让每个学校都收到,2,需要添加几条网络才能在任意一个学校分发都可以传遍所有学校。
分析:首先应该求出来连通分量,进行缩点,然后求每个分量的入度和出度,入度等于0的很明显都需要分发一个文件,至于需要添加几条边可以成为一个强连通,就是出度和入度最大的那个,因为需要把出度和入度相连。
****************************************************************
#include<stdio.h>
#include<string.h>
#include<stack>
#include<algorithm>
using namespace std;
const int MAXN = 105;
///邻接表变量
struct Edge{int v, next;}e[MAXN*MAXN];
int Head[MAXN], cnt;
void AddEdge(int u, int v)
{
e[cnt].v = v;
e[cnt].next = Head[u];
Head[u] = cnt++;
}
///tarjan算法变量
int sta[MAXN], inStack[MAXN], top;
int dfn[MAXN], low[MAXN], index;
int belong[MAXN], bnt;
void tarjan(int k)
{
int j;
dfn[k] = low[k] = ++index;
inStack[k] = true;
sta[++top] = k;
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] = false;
belong[j] = bnt;
}
while(k != j);
}
}
void InIt(int N)
{
cnt = bnt = index = 0;
top = 0;
for(int i=1; i<=N; i++)
{
Head[i] = -1;
dfn[i] = false;
}
}
int main()
{
int N;
while(scanf("%d", &N) != EOF)
{
int i, j, u, v;
InIt(N);
for(i=1; i<=N; i++)
{
while(scanf("%d", &v), v)
AddEdge(i, v);
}
for(i=1; i<=N; i++)if(!dfn[i])
tarjan(i);
int r[MAXN]={0}, c[MAXN]={0}, rn=0, cn=0;
for(i=1; i<=N; i++)
for(j=Head[i]; j!=-1; j=e[j].next)
{
u = belong[i], v = belong[e[j].v];
if(u != v)
{
c[u]++;
r[v]++;
}
}
for(i=1; i<=bnt; i++)
{
if(r[i] == 0)rn++;
if(c[i] == 0)cn++;
}
if(bnt == 1)
printf("1\n0\n");
else
printf("%d\n%d\n", rn, max(rn, cn));
}
return 0;
}