2018-team4-modules-有向图极大强连通分量(Kosaraju)
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
//x[i]:反向图的后序遍历
//CNT:强连通分量总数
//g[i]:记录i点所在强连通分量的编号
//Gt[i]:记录编号为i的强连通分量的点数
struct Edge{int b,n;}e[N];
int vis[N],x[N],h[N],g[N],Gt[N],t[N],tp,CNT;
void link(int a,int b) {e[++cnt] = (Edge){b,h[a]}, h[a] = cnt;}
//将边反向
void edgerev() {
for (int i=1;i<=n;i++) t[i] = h[i], h[i] = 0;
for (int u=1;u<=n;u++)
for (int i=t[u],v,w;i;i=w) {
v=e[i].b, w=e[i].n;
e[i] = (Edge){u,h[v]}, h[v] = i;
}
}
void dfs0(int u) {
vis[u] = 1;
for (int i=h[u],v;v=e[i].b,i;i=e[i].n)
if (!vis[v]) dfs0(v);
x[++tp] = u;
}
void dfs1(int u) {
vis[u] = 1;
for (int i=h[u],v;v=e[i].b,i;i=e[i].n)
if (!vis[v]) dfs1(v);
g[u] = CNT, Gt[CNT]++;
}
void solve() {
tp = cnt = CNT = 0;
edgerev();
for (int i=1;i<=n;i++) vis[i] = 0;
for (int i=1;i<=n;i++) if (!vis[i]) dfs0(i);
edgerev();
for (int i=1;i<=n;i++) vis[i] = 0;
for (int i=n;i>=1;i--) if (!vis[x[i]]) ++CNT, dfs1(x[i]);
}
}}}
//x[i]:反向图的后序遍历
//CNT:强连通分量总数
//g[i]:记录i点所在强连通分量的编号
//Gt[i]:记录编号为i的强连通分量的点数
struct Edge{int b,n;}e[N];
int vis[N],x[N],h[N],g[N],Gt[N],t[N],tp,CNT;
void link(int a,int b) {e[++cnt] = (Edge){b,h[a]}, h[a] = cnt;}
//将边反向
void edgerev() {
for (int i=1;i<=n;i++) t[i] = h[i], h[i] = 0;
for (int u=1;u<=n;u++)
for (int i=t[u],v,w;i;i=w) {
v=e[i].b, w=e[i].n;
e[i] = (Edge){u,h[v]}, h[v] = i;
}
}
void dfs0(int u) {
vis[u] = 1;
for (int i=h[u],v;v=e[i].b,i;i=e[i].n)
if (!vis[v]) dfs0(v);
x[++tp] = u;
}
void dfs1(int u) {
vis[u] = 1;
for (int i=h[u],v;v=e[i].b,i;i=e[i].n)
if (!vis[v]) dfs1(v);
g[u] = CNT, Gt[CNT]++;
}
void solve() {
tp = cnt = CNT = 0;
edgerev();
for (int i=1;i<=n;i++) vis[i] = 0;
for (int i=1;i<=n;i++) if (!vis[i]) dfs0(i);
edgerev();
for (int i=1;i<=n;i++) vis[i] = 0;
for (int i=n;i>=1;i--) if (!vis[x[i]]) ++CNT, dfs1(x[i]);
}