给n个学校间的有向传递关系,求最小的学校数,通过这些学校可以向所有学校传递消息,以及求最少需要加多少条有向边,使得这n个学校间两两可传递。
强连通分量缩点,缩点后入度为0点的个数即所需最小数量。记a为出度为0的点的个数,b为入度为0的点的个数,max(a,b)即为所需添加的最小边数。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int>g[110];
int dfn[110],low[110],st[110],vis[110],bel[110],top,cnt,sum;
int in[110],out[110];
void dfs(int u){
int i,v;
dfn[u]=low[u]=++cnt;
st[++top]=u;
vis[u]=1;
for(i=0;i<g[u].size();i++){
v=g[u][i];
if(dfn[v]==0){
dfs(v);
if(low[u]>low[v]) low[u]=low[v];
}
else if(vis[v]&&low[u]>dfn[v]) low[u]=dfn[v];
}
if(low[u]==dfn[u]){
vis[u]=0;
bel[u]=++sum;
while(st[top]!=u){
v=st[top];
bel[v]=sum;
vis[v]=0;
top--;
}
top--;
}
}
int main(){
int n,a,j,b,i;
scanf("%d",&n);
cnt=sum=top=0;
for(i=1;i<=n;i++){
while(scanf("%d",&a)){
if(a==0) break;
g[i].push_back(a);
}
}
for(i=1;i<=n;i++) if(dfn[i]==0) dfs(i);
for(i=1;i<=n;i++){
for(j=0;j<g[i].size();j++){
a=bel[g[i][j]];
b=bel[i];
if(a!=b){
out[b]++;
in[a]++;
}
}
}
a=b=0;
for(i=1;i<=sum;i++){
if(in[i]==0) a++;
if(out[i]==0) b++;
}
cout<<a<<endl;
if(a<b) swap(a,b);
if(sum==1) cout<<0<<endl;
else cout<<a<<endl;
return 0;
}