神仙的Tarjan算法,能否让我完全理解?

Tips

  • 有向图,缩强连通分量需要判断是否在栈,而无向图不需要。

求有向图的强连通分量

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int rd(){
	int res = 0, fl = 1; char c = getchar();
    while(!isdigit(c)){if(c == '-') fl = -1; c = getchar();}
    while(isdigit(c)){res = (res << 3) + (res << 1) + c - '0'; c = getchar();}
    return res * fl;
}
const int maxn = 1000010;
int n, m, en(1), fst[maxn], A, B;
int dfn[maxn], low[maxn], cnt, stk[maxn], top;
int bl[maxn], bcc, puted[maxn];
bool ins[maxn];
vector<int> Block[maxn];
struct Edge{
	int to, nxt;
}ed[maxn];
void add(int u, int v){
	ed[++en].to = v; ed[en].nxt = fst[u]; fst[u] = en; 
}
void tarjan(int u){
	dfn[u] = low[u] = ++cnt;
	stk[++top] = u;
	ins[u] = 1;
	for(int e(fst[u]), v(ed[e].to); e; e = ed[e].nxt, v = ed[e].to){
		if(!dfn[v]){
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(ins[v]) low[u] = min(low[u], dfn[v]);
	}
	if(dfn[u] == low[u]){
		bcc++;
		do{
			bl[stk[top]] = bcc;
			Block[bcc].push_back(stk[top]);
			ins[stk[top]] = 0;
		}while(stk[top--] != u);
	}
} 
int main(){
	n = rd(); m = rd();
	for(int i(1); i <= m; ++i){
		A = rd(); B = rd();
		add(A, B);
	}
	for(int i(1); i <= n; ++i){
		if(!dfn[i])tarjan(i);
	}
	printf("%d\n", bcc);
	for(int i(1); i <= n; ++i){
		if(!puted[bl[i]]){
			sort(Block[bl[i]].begin(), Block[bl[i]].end());
			int len = Block[bl[i]].size(); 
			for(int j(0); j < len; ++j){
				printf("%d ", Block[bl[i]][j]);
			} printf("\n");
			puted[bl[i]] = 1;
		}
	}
	return 0;
}

无向图如何找出割边?

单纯找割边的话完全用不到栈。

void Tarjan(int u, int fa){
	dfn[u] = low[u] = ++cnt;
	for(int e(fst[u]), v(ed[e].to); e; e = ed[e].nxt, v = ed[e].to){
		if((v == fa) || (v == u)) continue;
		if(!dfn[v]){
			Tarjan(v, u);
			low[u] = min(low[u], low[v]);
			if(low[v] > dfn[u]) Ans[++tot] = e; 
		}
		else low[u] = min(low[u], dfn[v]);
	}
}
posted @ 2021-09-25 21:18  _Buffett  阅读(51)  评论(0编辑  收藏  举报