POJ 1236 Network of Schools )
题目
题目很长,其实题意很简单,给一个有向图,问
- 最少从几个点出发能够走遍全图
- 最少加上几条边能够该图变为强连通图
分析
直接 T a r j i a n Tarjian Tarjian 缩点后分析 D A G DAG DAG 图的性质,从所有起点开始走就可以走遍全图,也就似乎度为 0 的点。而第二个问题,设建成的 D A G DAG DAG 图的入度,出度为 0 的节点数量为 a, b。保证 m a x ( a , b ) max(a,b) max(a,b) 条边加进去即可。
求 S C C SCC SCC 图的出入度表。先假设每个点都不相连,即初度入度都为 0 ,遇到 u 指向 v 的边,v 的入度,u 的出度都要为一。
后面要特判强连通图。/
代码
#include<cstdio>
#include <iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<stack>
using namespace std;
#define d(x) cout<<(x)<<endl
const int N = 1e3 + 10;
int n;
int pre[N], sccno[N], scc_cnt, low[N], dfs_clock;
vector<int> e[N];
stack<int> s;
void dfs(int u){
pre[u] = low[u] = ++dfs_clock;
s.push(u);
for(int i = 0; i < e[u].size(); i++){
int v = e[u][i];
if(!pre[v]){
dfs(v);
low[u] = min(low[u], low[v]);
}else if(!sccno[v]){
low[u] = min(low[u], pre[v]);
}
}
if(low[u] == pre[u]){
scc_cnt++;
while(1){
int x = s.top();
s.pop();
sccno[x] = scc_cnt;
if(x == u)
break;
}
}
}
void find_scc(){
memset(pre, 0, sizeof(pre));
memset(sccno, 0, sizeof(sccno));
dfs_clock = scc_cnt = 0;
for(int i = 1; i <= n; i++){
if (!pre[i]){
dfs(i);
}
}
}
void cal(){
int in[N], out[N];
for(int i = 1; i <= scc_cnt; i++)
in[i] = out[i] = 1;
for(int u = 1; u <= n; u++){
for(int i = 0; i < e[u].size(); i++){
int v = e[u][i];
if(sccno[u] != sccno[v])
in[sccno[v]] = out[sccno[u]] = 0;
}
}
int a = 0, b = 0;
for(int i = 1; i <= scc_cnt; i++){
if(in[i]) a++;
if(out[i]) b++;
}
printf("%d\n%d\n", a, max(a, b));
}
int main(){
scanf("%d", &n);
for(int i = 1, x; i <= n; i++){
while(scanf("%d", &x) && x){
e[i].push_back(x);
}
}
find_scc();
// d("fd");
if(scc_cnt == 1){
printf("1\n0\n");
}else{
cal();
}
return 0;
}