题意:
给定一个有向图,求有多少个顶点是由任何顶点出发都可达的。
顶点数<= 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; }
时间: 2024-10-06 08:42:31