Network of Schools |
---|
题意: 给定一个有向图,第一个问题问至少需要从几个点出发能到达全图,第二个问题问最少需要加多少条边使得全图变为强连通图。
题解: tarjan缩点之后入度为零的点的个数即为第一个问题的答案,第二个问题答案即为入度为零点个数与出度为零点个数中的较大值。
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
const int N = 110;
int n, x;;
int dfn, cnt, top;
int in[N], out[N];
int num[N], low[N];
int scc[N], sta[N];
vector<int> G[N], S[N];
void init() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
while(~scanf("%d", &x) && x)
G[i].push_back(x);
}
void dfs(int u) {
sta[top++] = u;
num[u] = low[u] = ++dfn;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(!num[v]) {
dfs(v);
low[u] = min(low[u], low[v]);
} else if(!scc[v])
low[u] = min(low[u], num[v]);
}
if(low[u] == num[u]) {
cnt++;
while(1) {
int v = sta[--top];
scc[v] = cnt;
if(u == v) break;
}
}
}
void tarjan() {
for(int i = 1; i <= n; i++) if(!num[i]) dfs(i);
}
void solve() {
for(int i = 1; i <= n; i++)
for(int j = 0; j < G[i].size(); j++) {
int u = scc[i], v = scc[G[i][j]];
if(u != v) {
S[u].push_back(v);
out[u]++, in[v]++;
}
}
}
int main() {
init(); tarjan(); solve();
int _in = 0, _out = 0;
for(int i = 1; i <= cnt; i++) {
if(in[i] == 0) _in++;
if(out[i] == 0) _out++;
}
if(cnt == 1)
printf("1\n0\n");
else
printf("%d\n%d\n", _in, max(_in, _out));
return 0;
}