Loading

算法笔记 - Kosaraju

概述

一个有向图求强联通分量的 \(Tarjan\) 平替。
通过两遍 \(dfs\) 来求解。

过程

\(Dfs\) 原图,在回溯时将节点入栈,扫描栈中的节点,如果未搜过就在反图开搜,将每次搜到的点归为一个 \(SCC\)


void Add(int u, int v) { e[u].push_back(v), g[v].push_back(u); }
void Dfs1(int u) { vis[u] = true; for (int v : e[u]) if (!vis[v]) Dfs1(v); d[++*d] = u; }
void Dfs2(int u) { bel[u] = scc; for (int v : g[u]) if (!bel[v]) Dfs2(v); }

int main() {
	lep(i, 1, 2 * n) if (!vis[i]) Dfs1(i);
	rep(i, 2 * n, 1) if (!bel[d[i]]) ++scc, Dfs2(d[i]);
}

证明

简单说明一下。
容易发现,我们在倒序扫描 \(Dfs\) 树的后缀遍历, \(SCC\) 的根会第一次被遍历到,而一个 \(SCC\) 在反向图上依旧是 \(SCC\) ,内部的所有点一定可以被正确加入。
那么我们可能会误将别的 \(SCC\) 中的点加入吗?
发现是不会的,因为在反图上,原本指出该 \(SCC\) 的边全部无法通行。
而原本指向该 \(SCC\) 的点,其一定会先于本 \(SCC\) 被染色。
算法正确性得证。

同时发现,\(SCC\) 的编号顺序即拓扑序。

例题

\(2-SAT\) 题目中使用最佳。
还有一些特殊的题目应用(待补)。

posted @ 2025-07-20 14:06  qkhm  阅读(17)  评论(0)    收藏  举报