引子
这是一篇久咕之作。
模板
todo
引导
首先,假设我们用的是前向星建图。
1 2 3 4 5 6 7 8 9 10
| struct Edge { int u, v, nx; } e[MAXN << 1];
int head[MAXN], cntEd;
inline void addEdge(int u, int v) { e[cntEd] = {u, v, head[u]}; head[u] = cntEd++; }
|
然后应该写一个DFS。
1 2 3 4 5 6 7 8 9
| void tarjan(int u) { for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v;
if ( ) { } } if ( ) { } }
|
下面想需要用到什么数组。
1 2 3 4
| int low[MAXN]; int dfn[MAXN], idx; int stk[MAXN], top; int scc[MAXN], sccnum;
|
然后想一下每个数组的意义,填进DFS。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| void tarjan(int u) { dfn[u] = low[u] = ++idx; stk[++top] = u;
for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v;
if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (!scc[v]) { low[u] = min(low[u], dfn[v]); } }
if (low[u] == dfn[u]) { sccnum++; int x; do { x = stk[top--]; scc[x] = sccnum; } while (x != u); } }
|
然后学会怎么用它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| int main() { memset(head, -1, sizeof head); int n; for (int i = 1; i <= n; ++i) { if (!dfn[i]) tarjan(i); } return 0; }
|
好了假装你会了。
当然要真的会了,可以试图去理解一下,DFS中的条件。
例题
给一个n点n边有向无权图。问,有多少种反转边的方案,使图中无简单环。
思路也简单,每条边反转和不反转有$2^n$种方案。假如有一个$m$阶环,有两种方案是不行的——全反转和全不反转。所以对每个$m_i$阶环,其实方案有$2^{m_i}-2$种方案。
其他边都当$2$累乘即可。
我的代码:60847488
Tarjan 1972