有向图强连通分量
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N = 10010; const int M = 10010; int n, m, top, num, tot = 0, sum = 0, st[N], last[M], to[M], dfn[N], low[N], vis[N], z[N]; void tarjan(int u) { dfn[u] = low[u] = ++tot; z[++top] = u; vis[u] = 1; for (int i = st[u]; i ; i = last[i]) { if (!dfn[to[i]]) { tarjan(to[i]); low[u] = min(low[u], low[to[i]]); } else if (vis[to[i]]) low[u] = min(low[u], low[to[i]]); } if (dfn[u] == low[u]) { do { printf("%d ", z[top]); vis[z[top]] = 0; top--; }while (u != z[top + 1]); printf("\n"); } } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); to[i] = v; last[i] = st[u]; st[u] = i; } for (int i = 1; i <= n; i++) if (!dfn[i]) { memset(z, 0, sizeof z); top = 0; tarjan(i); } return 0; }
割点
两个割点之间即为点双,030
例题:JZOJ 3896
#include<cstdio> #include<iostream> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N = 50010; const int M = 200010; int n, m, tot = 0, cnt = 0, st[N], last[M], to[M], dfn[N], low[N], ans[N], t[N], vis[N]; void add(int u, int v) { to[++cnt] = v; last[cnt] = st[u]; st[u] = cnt; } void tarjan(int u, int f) { dfn[u] = low[u] = ++tot; int sum = 0; for (int i = st[u]; i ; i = last[i]) { if (!dfn[to[i]]) { tarjan(to[i], u); low[u] = min(low[u], low[to[i]]); if (low[to[i]] >= dfn[u] && !vis[u]) { vis[u] = 1; ans[++ans[0]] = u; } } else if (to[i] != f) low[u] = min(low[u], dfn[to[i]]); } } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); add(u, v); add(v, u); t[i] = 1; } tarjan(1, 0); sort(ans + 1, ans + ans[0] + 1); for (int i = 1; i <= n; i++) printf("%d ", ans[1]); return 0; }
桥
两条桥之间即为边双,030
把割点稍加修改即可
缩点
把联通分量缩成一个点0.0