xg
题意
N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
思路
对于强连通分量,可以看作一个整体,然后进行缩点。
至少提供多少个软件,其实就是求入度为0的点的个数。
若使得一个DAG成为强连通图,实际就是零入度点的个数和零出度点的个数的最大值。所有都不需要建新图。
特判一下已经是强连通图的情况。
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <string> #include <map> #include <iomanip> #include <algorithm> #include <queue> #include <stack> #include <set> #include <vector> #define bug cout<<"--------------"<<endl #define sp ' ' using namespace std; typedef long long ll; const int maxn = 1e5+10; int tot = 0; int head[maxn],ver[maxn],edge[maxn],nextt[maxn]; void add(int x,int y) { ver[++tot] = y,nextt[tot] = head[x] , head[x] = tot; } int dfn[maxn],low[maxn],sta[maxn],c[maxn],ins[maxn]; vector<int>scc[maxn]; int in[maxn],out[maxn]; int n,num,top,cnt; void tarjan(int x) { dfn[x]=low[x]=++num; sta[++top]=x,ins[x]=1; for(int i=head[x];i;i=nextt[i]) { int y=ver[i]; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); } else if(ins[y]){ low[x]=min(low[x],dfn[y]); } } if(dfn[x]==low[x]){ cnt++;int y; do{ y=sta[top--],ins[y]=0; c[y]=cnt,scc[cnt].push_back(y); }while(x!=y); } } int main() { //freopen("input.txt", "r", stdin); scanf("%d",&n); for(int i = 1;i <= n; ++i){ int y ; while(scanf("%d",&y)){ if(y == 0) break; add(i,y); } } for(int i =1 ;i <=n ;++i){ if(!dfn[i]) tarjan(i); } for(int x =1 ;x <=n ;++x){ for(int i =head[x] ;i;i = nextt[i]){ int y = ver[i]; if(c[x] == c[y]) continue; // addc(c[x],c[y]); in[c[y]]++; out[c[x]]++; } } //nub_edge = tc,nub_point = cnt; if(cnt == 1) { printf("1 0"); return 0; } int innub = 0,outnub = 0; for(int i = 1;i <= cnt;++i){ if(!in[i]) innub++; if(!out[i]) outnub++; } printf("%d %d",innub,max(innub,outnub) ); }