引子
这是一篇久咕之作。
模板
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