这个本来是暑假的时候学图连通性的时候一起学的。没整理出来,又有些遗忘。
现在在 2-sat 里用到它来缩点。先写个简略版的。
算法:
dfn[]、low[]初始为++num(排除0),
tarjin到u入栈s,ins[u] = 1;
遍历u的所有邻点v(邻接表),
对没有tarjin的点(dfn[v]=0),tarjin(v),low[u] = min(low[u], low[v])。
对tarjin过,并还在栈中的点,low[u] = min(low[u], dfn[v])。
遍历完后,
如果dfn[u] == low[u],
栈顶v出栈,直到u==v。同一时间出栈的即为一个强连通分量。
代码:
// 求 有向图 强连通分支 tarjin算法 // 类似求 无向图 割点、桥、双连通分支 #include<cstdio> #include<cstring> #include<iostream> #include<stack> using namespace std; #define FF(x1, x2) for(int i=x1;i<x2; i++) #define TOMIN(x1, x2) x1=x1<x2?x1:x2; #define MAXN 100 #define MAXM 100 struct edge{int u, v;} a[MAXM]; int first[MAXN], next[MAXM]; int n, m; void addedge(int u, int v, int e) {next[e]=first[u]; first[u]=e; a[e].u=u; a[e].v=v;} void read_graph() {cin>>n>>m; FF(0, m){int u,v; cin>>u>>v; addedge(u, v, i);} } int dfn[MAXN], low[MAXN]; int num; stack<int> s; int ins[MAXN]; void tarjin(int u) { dfn[u] = low[u] = ++num; s.push(u); ins[u] = 1; for(int e=first[u]; e!=-1; e=next[e]) { int v=a[e].v; if(!dfn[v]) { tarjin(v); TOMIN(low[u], low[v]); } else if(ins[v]) { TOMIN(low[u], dfn[v]); } } if(dfn[u]==low[u]) { while(1) { int v=s.top(); s.pop(); ins[v] = 0; cout<<v<<" "; if(u == v) break; } cout<<endl; } } int main() { num=0; //点赋值 memset(dfn, 0, sizeof(dfn)); memset(first, -1, sizeof(first)); memset(ins, 0, sizeof(ins)); read_graph(); FF(1, n+1) { if(!dfn[i]) tarjin(i); } } /* input 6 8 1 3 3 5 5 6 1 2 4 1 2 4 4 6 3 4 output 6 5 3 4 2 1 */