F:这道题真的是做了一天,本想编造自己的模板,可是却错误百出,最后还是借鉴了kuangbin的模板。
题解:
- 强连通分量缩点求入度为0的个数和出度为0的分量个数
- 题目大意:N(2<N<100)各学校之间有单向的网络,
- 每个学校得到一套软件后,可以通过单向网络向周边的学校传输,
- 问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。
- 2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,
- 经过若干次传送,网络内所有的学校最终都能得到软件。
- 也就是:
- 给定一个有向图,求:
- 1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
- 2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点
- 顶点数<= 100
- 解题思路:
- 1. 求出所有强连通分量
- 2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
- 3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少
- 在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
- 加边的方法:
- 要为每个入度为0的点添加入边,为每个出度为0的点添加出边
- 假定有 n 个入度为0的点,m个出度为0的点,如何加边?
- 把所有入度为0的点编号 0,1,2,3,4 ....N -1
- 每次为一个编号为i的入度0点可达的出度0点,添加一条出边,连到编号为(i+1)%N 的那个出度0点,
- 这需要加n条边
- 若 m <= n,则
- 加了这n条边后,已经没有入度0点,则问题解决,一共加了n条边
- 若 m > n,则还有m-n个入度0点,则从这些点以外任取一点,和这些点都连上边,即可,这还需加m-n条边。
- 所以,max(m,n)就是第二个问题的解
- 此外:当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为0的都有一个,但是实际上不需要增加清单的项了,所以答案是1,0;
-
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<algorithm> #include<limits.h> #include<vector> #include<queue> #include<math.h> #include<stack> using namespace std; #define maxn 105 int dfn[maxn],low[maxn]; vector<int>q[maxn]; stack<int>s; int time,n,m,sum; int belong[maxn]; int in[maxn],out[maxn]; void tarjan(int u); void solve() { int i,j; time=sum=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(belong,0,sizeof(belong)); for(i=0;i<n;i++) if(!dfn[i]) tarjan(i); } void tarjan(int u) { int i,j; dfn[u]=low[u]=++time; s.push(u); for(i=0;i<q[u].size();i++) { int v=q[u][i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(!belong[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { sum++; while(1) { j=s.top(); s.pop(); belong[j]=sum; if(u==j) break; } } } int main() { int i,j; scanf("%d",&n); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); for(i=0;i<n;i++) { while(scanf("%d",&m),m!=0) { m=m-1; q[i].push_back(m); } } solve(); if(sum==1) { printf("1\n0\n"); return 0; } for(i=0;i<n;i++) { for(j=0;j<q[i].size();j++) { int v=q[i][j]; if(belong[i]!=belong[v]) { in[belong[v]]++; out[belong[i]]++; } } } int x=0,y=0; for(i=1;i<=sum;i++) { if(!in[i]) x++; if(!out[i]) y++; } printf("%d\n%d\n",x,max(x,y)); }