强连通缩点

xiaoxiao2021-02-28  8

强连通分量+缩点+拓扑排序 模板

(强连通建立新图)(tarjan找强连通分量)

#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> typedef long long ll; const constexpr int maxN = 1e6+3; typedef int int_vec[maxN]; struct dag_helper { int n,t; dag_helper(int _n=-1,int _t=0):n(_n),t(_t) {} bool operator<(const dag_helper& d) const { return t > d.t; } }; int V,E; int_vec head,to,next,dfn,low,belong,S,end; int edge_count,time,scc_count,scc_edge_count,top,time_2; dag_helper helper[maxN]; void init() { std::fill_n(head,maxN,-1); std::fill_n(to,maxN,-1); std::fill_n(next,maxN,-1); std::fill_n(dfn,maxN,0); std::fill_n(low,maxN,0); std::fill_n(belong,maxN,-1); std::fill_n(end,maxN,0); scc_edge_count = 0; edge_count = 0; time = 0; scc_count = 0; top = -1; time_2 = 0; } void add(int u,int v) { to[edge_count] = v; next[edge_count] = head[u]; head[u] = edge_count++; } void scc_add(int u,int v) { u += V; v += V; to[edge_count+scc_edge_count] = v; next[edge_count+scc_edge_count] = head[u]; head[edge_count+scc_edge_count] = edge_count+scc_edge_count; ++scc_edge_count; } void targan(int x) { if (dfn[x]) return; dfn[x] = low[x] = ++time; S[++top] = x; for (int i=head[x];i>=0;i=next[i]) { int y = to[i]; if (!dfn[y]) { targan(y); if (low[x] > low[y]) low[x] = low[y]; } else if ((belong[y] == -1) and (low[x] > dfn[y])) low[x] = dfn[y]; } if (dfn[x] == low[x]) { while (true) { belong[S[top]] = scc_count; if (S[top--] == x) break; } ++scc_count; } } void shrink() { for (int i=0;i<V;++i) for (int j=head[i];j>=0;j=next[j]) { int t = to[j]; if (belong[i] != belong[t]) scc_add(belong[i],belong[t]); } } void dfs(int x) { for (int i=head[x];i>=0;i=next[i]) { int y = to[i]; if (!end[y]) dfs(y); } end[x] = ++time_2; } void dag() { for (int i=0;i<scc_count;++i) dfs(V+i); for (int i=0;i<scc_count;++i) { helper[i].t = end[V+i]; helper[i].n = i; } std::sort(helper,helper+scc_count); } void doit() { for (int i=0;i<V;++i) targan(i); shrink(); dag(); } int main() { V = 8; init(); add(0,1); add(1,2); add(1,4); add(1,5); add(2,3); add(2,6); add(3,2); add(3,7); add(4,0); add(4,5); add(5,6); add(6,5); add(6,7); add(7,7); doit(); for (int i=0;i<V;++i) std::printf("%d\n",belong[i]); for (int i=0;i<scc_count;++i) std::printf("%d %d\n",helper[i].n,helper[i].t); std::printf("FIN\n"); }

注:

1.S为stack,可以用std::stack替代

2.helper最后的排序即为对应强连通分量的拓扑序(注意编号)

3.每个节点i属于belong[i]分量

4.节点编号、边编号从0开始,强联通节点编号从V开始,强联通边编号从E开始(初始时E == edge_count)

转载请注明原文地址: https://www.6miu.com/read-200386.html

最新回复(0)