题目大意
有 n(2<=n<=100) 所学校,每个学校都有个 list,列出了这个学校提供软件的学校名单。
现在问:
A、为了使所有的学校享用到一个软件,最少有多少学校要 copy 一个软件
B、为了使传到任意学校的软件能够传到其他所有的学校,至少要添加多少个学校到相应学校的 list 中去
做法分析
这种题,显然要先给图“化简”,是其成为一个 DAG 图
对于 task A,我们只需统计“化简”后的 DAG 中入度为 0 的点的个数
对于 task B,其实就是求添加多少条边使得 DAG 之间的所有点能够相互到达(形成一个 SCC),有一个结论:答案是入度为 0 的点的个数和出度为 0 的点个数的最大者
参考代码

1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <vector> 5 #include <stack> 6 7 using namespace std; 8 9 const int N=106; 10 11 vector <int> arc[N]; 12 int dfn[N], low[N], id[N]; 13 int n, T, ind; 14 stack <int> s; 15 bool vs[N]; 16 17 void tarjan(int u) 18 { 19 vs[u]=1, s.push(u); 20 dfn[u]=low[u]=T++; 21 int len=(int)arc[u].size(); 22 for(int i=0; i<len; i++) 23 { 24 int v=arc[u][i]; 25 if(dfn[v]==-1) 26 { 27 tarjan(v); 28 if(low[u]>low[v]) low[u]=low[v]; 29 } 30 else if(vs[v] && low[u]>dfn[v]) low[u]=dfn[v]; 31 } 32 if(low[u]==dfn[u]) 33 { 34 for(int v; 1; ) 35 { 36 v=s.top(); 37 s.pop(), vs[v]=0; 38 id[v]=ind; 39 if(v==u) break; 40 } 41 ind++; 42 } 43 } 44 45 int main() 46 { 47 scanf("%d", &n); 48 for(int i=1, u; i<=n; i++) 49 { 50 arc[i].clear(); 51 while(scanf("%d", &u), u!=0) arc[i].push_back(u); 52 } 53 for(int i=1; i<=n; i++) dfn[i]=-1, vs[i]=0; 54 while(!s.empty()) s.pop(); 55 ind=T=0; 56 for(int i=1; i<=n; i++) if(dfn[i]==-1) tarjan(i); 57 for(int i=0; i<ind; i++) dfn[i]=low[i]=0; 58 for(int i=1; i<=n; i++) 59 { 60 int len=(int)arc[i].size(), u=id[i]; 61 for(int j=0; j<len; j++) 62 { 63 int v=id[arc[i][j]]; 64 if(u!=v) dfn[u]++, low[v]++; 65 } 66 } 67 int ans1=0, ans2=0; 68 for(int i=0; i<ind; i++) 69 { 70 if(low[i]==0) ans1++; 71 if(dfn[i]==0) ans2++; 72 } 73 ans2=max(ans1, ans2); 74 if(ind==1) ans1=1, ans2=0; 75 printf("%d\n%d\n", ans1, ans2); 76 return 0; 77 }