题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
考虑问题1:对于每个强连通分量最多需发放1个,再看其与其他强连通分量,如果强连通分量A与B,A->B可以传输,则只需在A发放软件。于是,求出强连通分量并进行缩点后,统计一下入度为0的点个数就是答案。
考虑问题2:问题的本质就是添加尽量少的边使得新图强连通。由于缩点后得到的是DAG图(两点之间最多只有1条边),于是只需求出统计点的入度和出度取最大值就是答案。注意原图本身就是强连通的情况就好了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
using namespace std;
#define N 105
vector<int> G[N];
int pre[N],low[N],sccno[N],dfs_clock,scc_cnt,cnt[N];
stack<int>S;
void dfs(int u){
pre[u]=low[u]=++dfs_clock;
S.push(u);
for(int i=0;i<G[u].size();++i){
int v=G[u][i];
if(!pre[v]){
dfs(v);
low[u]=min(low[u],low[v]);
}else if(!sccno[v])
low[u]=min(low[u],pre[v]);
}
if(low[u]==pre[u]){
cnt[++scc_cnt]=0;
for(;;){
int x=S.top();S.pop();
sccno[x]=scc_cnt;
++cnt[scc_cnt];
if(x==u) break;
}
}
}
void find_scc(int n){
dfs_clock=scc_cnt=0;
memset(sccno,0,sizeof(sccno));
memset(pre,0,sizeof(pre));
for(int i=0;i<n;++i) if(!pre[i]) dfs(i);
}
int in[N],out[N];
int main()
{
int i,j,n,x;
while(~scanf("%d",&n))
{
for(i=0;i<n;++i){
G[i].clear();
while(~scanf("%d",&x)&&x) G[i].push_back(--x);
}
find_scc(n);
if(scc_cnt==1) {printf("1\n0\n");continue;}
for(i=1;i<=scc_cnt;++i) in[i]=out[i]=0;
for(i=0;i<n;++i)
for(j=0;j<G[i].size();++j){
int v=G[i][j];
if(sccno[v]!=sccno[i]) {++in[sccno[v]];++out[sccno[i]];}
}
int ans1=0,ans2=0;
for(i=1;i<=scc_cnt;++i)
{
if(!in[i]) ++ans1;
if(!out[i]) ++ans2;
}
printf("%d\n%d\n",ans1,max(ans1,ans2));
}
return 0;
}