链接:http://poj.org/problem?id=1236
题意:有一个由若干个学校组成的网络。每个学校与其相连(有向边)的学校构成一个“receiving schools”,即这个学校
可以发送文件至这些“receiving schools”。有一个A任务:最少需要几份原文件,使得每个人都能接收到文件。B任务:最
少添加几条边,使得无论从哪一个学校发送原文件,使得每个学校都能收到文件。
A任务:有向图求连通分量,然后缩点,求每个缩点的入度。所有缩点中,入度为零的点即为所需的原文件数(即这些学校
必须发一份原文件,否则不能保证每个学校都能收到文件)。
B任务:求出连通分量后,缩点,添加边使其变成强连通图。计算每个缩点的出度和入度。记出度为0的缩点个数为outd,入度为0的缩点个数为ind。
则,所需添加的边的数目为max(ind,outd)。
#include<cstdio>
#include<cstring>
#define MAXN 105
#define MAX(a,b) a>b?a:b
using namespace std;
struct Edge
{
int to;
int next;
}edge[MAXN*MAXN];
int head[MAXN],dfn[MAXN],low[MAXN];
int degree[MAXN][2],belong[MAXN],stack[MAXN],instack[MAXN];
int index,bcnt,ecnt,top;
int n;
void add(int u,int v)
{
edge[ecnt].to=v;
edge[ecnt].next=head[u];
head[u]=ecnt++;
}
void tarjan(int u)
{
int i,v;
dfn[u]=low[u]=++index;
stack[top++]=u;
instack[u]=1;
for(i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(!dfn[v])
{
tarjan(v);
if(low[u]>low[v])
low[u]=low[v];
}
else if(instack[v]&&low[u]>dfn[v])
low[u]=dfn[v];
}
if(dfn[u]==low[u])
{
bcnt++;
do{
v=stack[--top];
instack[v]=0;
belong[v]=bcnt;
}while(u!=v);
}
}
int main()
{
int a,b;
int ind,outd;
while(scanf("%d",&n)!=EOF)
{
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
memset(degree,0,sizeof(degree));
ecnt=index=bcnt=top=0;
for(a=1;a<=n;a++)
while(scanf("%d",&b),b)
add(a,b);
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;i++)
for(int j=head[i];j!=-1;j=edge[j].next)
if(belong[i]!=belong[edge[j].to])
{
degree[belong[i]][0]++;
degree[belong[edge[j].to]][1]++;
}
ind=outd=0;
for(int i=1;i<=bcnt;i++)
{
if(degree[i][0]==0)
outd++;
if(degree[i][1]==0)
ind++;
}
int max=MAX(ind,outd);
if(bcnt==1)max=0;//如果连通块只有一个,则加入0条边
printf("%d\n",ind);
printf("%d\n",max);
}
}