题意:
给出n个学校,每个学校都有receiving school,第一问求的是从外部分发给最少的学校,所有的学校都能收到,第二问就是加多少receiving school可以使得从任意学校发一个软件,其他全部学校都能收到。
思路:
求出强连通分量后,将每个强连通分量缩成一个点,得到一个DAG。接下来第一问的答案就是入度为0的点的个数,第二问是入度为0的点的个数与出度为0的个数两者的最大值。
(当整个图都是连通,即只有一个强连通分量时,第一问答案是1,第二问答案是0)
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <stack>
#include <vector>
#include <string.h>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int MAXN=110;
struct _Edge
{
int frm,to,next;
}edge[MAXN*MAXN];
int hd[MAXN],tot;
int Low[MAXN],Sta1[MAXN],Sta2[MAXN],Belong[MAXN];
int num[MAXN];//下标1~scc
bool in[MAXN],out[MAXN];
int scc,Index,stp1,stp2;
void addedge(int u,int v)
{
edge[tot].frm=u;
edge[tot].to=v;
edge[tot].next=hd[u];
hd[u]=tot++;
}
void Garbowbfs(int u)
{
Sta1[stp1++]=u;
Sta2[stp2++]=u;
Low[u]=++Index;
for(int i=hd[u];i!=-1;i=edge[i].next)
{
if(!Low[edge[i].to])
Garbowbfs(edge[i].to);
else if(!Belong[edge[i].to]){
while(Low[Sta2[stp2-1]]>Low[edge[i].to])
--stp2;
}
}
if(Sta2[stp2-1]==u){
stp2--;
scc++;
int v;
do{
v=Sta1[--stp1];
num[scc]++;
Belong[v]=scc;
}while(v!=u);
}
}
int main(int argc, char const *argv[])
{
int n;
cin>>n;
msc(hd);
ms(in);
tot=0;
for(int i=1;i<=n;i++)
{
int tmp;
while(scanf("%d",&tmp)!=EOF&&tmp)
addedge(i,tmp);
}
scc=Index=stp1=stp2=0;
ms(Belong);
ms(Low);
ms(num);
for(int i=1;i<=n;i++)
if(!Low[i]) Garbowbfs(i);
if(scc==1) {puts("1\n0");return 0;}
for(int i=0;i<tot;)
{
edge[i].frm=Belong[edge[i].frm];
edge[i].to=Belong[edge[i].to];
if(edge[i].frm==edge[i].to)
swap(edge[i],edge[--tot]);
else i++;
}
ms(in);
ms(out);
int in0=0,out0=0;
for(int i=0;i<tot;i++)
in[edge[i].to]=out[edge[i].frm]=true;
for(int i=1;i<=scc;i++)
{
if(!in[i]) in0++;
if(!out[i]) out0++;
}
printf("%d\n%d\n",in0,max(in0,out0) );
return 0;
}