Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 13325 | Accepted: 5328 |
Description
Input
Output
Sample Input
5 2 4 3 0 4 5 0 0 0 1 0
Sample Output
1 2
以下解析转自斌神的博客
强连通分量缩点求入度为0的个数和出度为0的分量个数
题目大意:N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。2,至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。
也就是:
— 给定一个有向图,求:
1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点
解题思路:
— 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 <cstdio> #include <algorithm> #include <cstring> #include <vector> #define maxn 100 + 100 #define maxm 110 * 100 using namespace std; int n, m; struct node{ int u, v, next; }; node edge[maxm]; int head[maxn], cnt; int low[maxn], dfn[maxn]; int dfs_clock; int Stack[maxn], top; bool Instack[maxn]; int Belong[maxn]; int scc_clock; int in[maxn], out[maxn]; int num[maxn]; void init(){ cnt = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v){ edge[cnt] = {u, v, head[u]}; head[u] = cnt++; } void getmap(){ for(int i = 1; i <= n; ++i){ int v; while(scanf("%d", &v),v){ addedge(i, v); } } } void Tarjan(int u, int per){ int v; low[u] = dfn[u] = ++dfs_clock; Stack[top++] = u; Instack[u] = true; for(int i = head[u]; i != -1; i = edge[i].next){ int v = edge[i].v; if(!dfn[v]){ Tarjan(v, u); low[u] = min(low[u], low[v]); } else if(Instack[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]){ scc_clock++; do{ v = Stack[--top]; Instack[v] = false; Belong[v] = scc_clock; } while( v != u); } } void suodian(){ for(int i = 1; i <= scc_clock; ++i){ out[i] = 0; in[i] = 0; } for(int i = 0; i < cnt; ++i){ int u = Belong[edge[i].u]; int v = Belong[edge[i].v]; if(u != v){ out[u]++; in[v]++; } } } void find(){ memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(Belong, 0, sizeof(Belong)); memset(Stack, 0, sizeof(Stack)); memset(Instack, false, sizeof(false)); dfs_clock = scc_clock = top = 0; for(int i = 1; i <= n ; ++i){ if(!dfn[i]) Tarjan(i, i); } } void solve(){ if(scc_clock == 1){ printf("1\n0\n"); return ; } int numin, numout; numin = numout = 0; for(int i = 1; i <= scc_clock; ++i){ if(in[i] == 0) numin++; if(out[i] == 0) numout++; } printf("%d\n%d\n", numin, max(numout, numin)); } int main (){ while(scanf("%d", &n) != EOF){ init(); getmap(); find(); suodian(); solve(); } return 0; }