https://www.luogu.org/problem/show?pid=2002
SCC缩点的模板题,缩点后统计入度为0的点的数量就完了。
#include <iostream> #include <vector> #include <stack> #include <cstring> #define maxn 100005 using namespace std; int n, m; vector<int> g[maxn], g2[maxn]; int indegree[maxn]; int timer = 0, cnter = 0; int dfn[maxn], low[maxn], scc[maxn]; stack<int> sta; bool insta[maxn]; void dfs(int v) { /* low[v]=min{ dfn[v], low[w], 存在有向边(v,w)且搜索到v时w尚未被搜索到 dfn[w] 存在有向边(v,w)且搜索到v时w在栈内 } */ low[v] = dfn[v] = ++timer; sta.push(v); insta[v] = true; for (int i = 0; i < g[v].size(); i++) { int w = g[v][i]; if (!dfn[w]) { dfs(w); low[v] = min(low[v], low[w]); } else if (insta[w]) { low[v] = min(low[v], dfn[w]); } } if (dfn[v] == low[v]) { ++cnter; int t; do { t = sta.top(); sta.pop(); insta[t] = false; scc[t] = cnter; } while (t != v); } } void tarjan_scc() { for (int i = 1; i <= n; i++) { if (!dfn[i]) dfs(i); } } void contract() { for (int v = 1; v <= n; v++) { for (int i = 0; i < g[v].size(); i++) { // 对于边(v,w),若v与w不在同一SCC,则该边在缩点后的新图为(scc[v],scc[w]) int w = g[v][i]; if (scc[v] != scc[w]) { g2[scc[v]].push_back(scc[w]); indegree[scc[w]]++; } } } } int main() { ios::sync_with_stdio(false); cin >> n >> m; int u, v; for (int i = 1; i <= m; i++) { cin >> u >> v; g[u].push_back(v); } tarjan_scc(); contract(); // 统计得到的DAG中入度为0的点 int ans = 0; for (int i = 1; i <= cnter; i++) { if (!indegree[i]) ans++; } cout << ans << endl; return 0; }
时间: 2024-10-26 17:18:15