题意:
给定一个有向图,求有多少个顶点是由任何顶点出发都可达的。
顶点数<= 10,000,边数 <= 50,000
定理:
有向无环图中唯一出度为0的点,一定可以由任何点出发均可达
(由于无环,所以从任何点出发往前走,必然终止于一个出度为0的点)
1. 求出所有强连通分量
2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
3. DAG上面如果有唯一的出度为0的点,则该点能被所有的点可达。那么该点所代表的连通分量上的所有的原图中的点,都能被原图中的所有点可达,则该连通分量的点数,就是答案。
4. DAG上面如果有不止一个出度为0的点,则这些点互相不可达,原问题无解,答案为0
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 10000 + 100;
vector<int> g[maxn];
int dfn[maxn], low[maxn], belong[maxn], dfs_clock, scc_cnt, size[maxn];
stack<int> s;
int n, m;
void dfs(int u){
dfn[u] = low[u] = ++dfs_clock;
s.push(u);
for(int i=0; i<g[u].size(); ++i){
int v = g[u][i];
if(!dfn[v]){
dfs(v);
low[u] = min(low[u], low[v]);
}else if(!belong[v]){
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]){
scc_cnt++;
for(;;){
int x = s.top(); s.pop();
belong[x] = scc_cnt;
size[scc_cnt]++;
if(x == u) break;
}
}
}
void find_scc(int n){
dfs_clock = scc_cnt = 0;
memset(belong, 0, sizeof belong );
memset(dfn, 0, sizeof dfn );
for(int i=1; i<=n; ++i)
if(!dfn[i]) dfs(i);
}
int main(){
scanf("%d%d", &n, &m);
int u, v;
for(int i=0; i<m; ++i){
scanf("%d%d", &u, &v);
g[u].push_back(v);
}
find_scc(n);
int out[maxn];
memset(out, 0, sizeof out );
for(int i=1; i<=n; ++i){
for(int j=0; j<g[i].size(); ++j){
int &v = g[i][j];
if(belong[i] != belong[v]){
out[belong[i]]++;
}
}
}
int cnt = 0, ans;
for(int i=1; i<=scc_cnt; ++i){
if(out[i]==0){
cnt++;
ans = size[i];
}
}
if(cnt==1){
printf("%d\n", ans);
}else {
printf("0\n");
}
return 0;
}