题目大意:
给定一个有向图,求:
1) 至少要选几个顶点,才能做到从这些顶点出
发,可以到达全部顶点
2) 至少要加多少条边,才能使得从任何一个顶
点出发,都能到达全部顶点
顶点数<= 100
有用的定理:
有向无环图中所有入度不为0的点,一定可以由某个入度为0的点出发可达。由于无环,所以从任何入度不为0的点往回走必然终止于一个入度为0的点
解题思路:
1. 求出所有强连通分量
2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少
在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
加边的方法:要为每个入度为0的点添加入边,为每个出度为0的点添加出边假定有 n 个入度为0的点,m个出度为0的点,max(m,n)就是第二个问题的解(证明难,略)
当我们求出强联通分量之后就可以,然后重新构图, 最后得出结果, 有一个答案要特殊判断一下, 因为只有一个强联通分量的时候是不需要多加边,因此要特殊判断一下。
#include <iostream> #include <cstdlib> #include <cstdio> #include <algorithm> #include <vector> #include <queue> #include <cmath> #include <stack> #include <cstring> using namespace std; #define INF 0xfffffff #define maxn 106 #define min(a,b) (a<b?a:b) #define max(a,b) (a>b?a:b) stack<int> S; bool inStack[maxn]; int low[maxn],dfn[maxn], n, time, belong[maxn], cnt; bool G[maxn][maxn]; void init() { memset(inStack, false, sizeof(inStack)); memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(G, false, sizeof(G)); memset(belong, 0, sizeof(belong) ); cnt = time = 1; } void tarjan(int u) { low[u] = dfn[u] = time ++; S.push(u); inStack[u] = true; int i, v; for(i=1; i<=n; i++) { if(!G[u][i]) continue; if( !low[i]) { tarjan(i); low[u] = min(low[u], low[i]); } else if( inStack[i] ) { low[u] = min(low[u], dfn[i]); } } if(low[u] == dfn[u]) { do { v = S.top(); S.pop(); inStack[v] = false; belong[v] = cnt; } while(u != v); cnt ++; } } void solve() { int in[maxn] = {0}, out[maxn] = {0}, a, b; bool maps[maxn][maxn] = {0}; int i, j; for(i=1; i<=n; i++) { if(!low[i]) tarjan(i); } for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { if(G[i ][j ] && belong[i] != belong[j]) { maps[belong[i] ][belong[j] ] = true; } } } a = b = 0; for(i=1; i<cnt; i++) { for(j=1; j<cnt; j++) { if(maps[i][j]) { in[j] ++; out[i] ++; } } } for(i=1; i<cnt; i++) { if(in[i] == 0) a ++; if(out[i] == 0) b ++; } printf("%d\n", a); if(cnt == 2) printf("0\n"); else printf("%d\n", max(a,b) ); } int main() { int i, a; while(scanf("%d",&n) != EOF) { init(); for(i=1; i<=n; i++) { while(scanf("%d",&a), a) { G[i][a] = true; } } solve(); } return 0; }