【图论】双连通总结
双连通总结
这类问题分为,边-双连通。点-双连通
边双连通
边双连通,求出来后。连接没一个双连通的分量的就是割边,因此能够缩点成一棵树。把问题转化为在树上搞,割边的定义为:去掉这条边后图将不连通
基本这类题都一个解法。求双连通分量,然后缩点成树,进行操作
或者就是直接要求割边,做跟割边相关的操作
模板:
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> using namespace std; const int N = 10005; const int M = 20005; int n, m, val[N]; struct Edge { int u, v, id; bool iscut; Edge() {} Edge(int u, int v, int id) { this->u = u; this->v = v; this->id = id; this->iscut = false; } } edge[M * 2], cut[M]; int en, first[N], next[M], cutn; void init() { memset(first, -1, sizeof(first)); en = 0; } void add_edge(int u, int v, int id) { edge[en] = Edge(u, v, id); next[en] = first[u]; first[u] = en++; } int pre[N], dfn[N], bccno[N], bccn, dfs_clock; void dfs_cut(int u, int fa) { pre[u] = dfn[u] = ++dfs_clock; for (int i = first[u]; i + 1; i = next[i]) { int v = edge[i].v; if (edge[i].id == fa) continue; if (!pre[v]) { dfs_cut(v, edge[i].id); dfn[u] = min(dfn[u], dfn[v]); if (dfn[v] > pre[u]) { edge[i].iscut = edge[i^1].iscut = true;//标记割边 cut[cutn++] = edge[i];//存放割边 } } else dfn[u] = min(dfn[u], pre[v]); } } void find_cut() { dfs_clock = cutn = 0; memset(pre, 0, sizeof(pre)); for (int i = 0; i < n; i++) if (!pre[i]) dfs_cut(i, -1); } void dfs_bcc(int u) { pre[u] = 1; bccno[u] = bccn; for (int i = first[u]; i + 1; i = next[i]) { if (edge[i].iscut) continue; int v = edge[i].v; if (pre[v]) continue; dfs_bcc(v); } } vector<int> bcc[N]; void find_bcc() { bccn = 0; memset(pre, 0, sizeof(pre)); for (int i = 0; i < n; i++) { if (!pre[i]) { dfs_bcc(i); bccn++; } } } int main() { return 0; }
HDU 2242 考研路茫茫——空调教室 边双连通缩点+dfs
HDU 2460 Network 边双连通缩点+树链剖分
HDU 3849By Recognizing These Guys, We Find Social Networks Useful 求桥
HDU 4005 The war 边双连通缩点+dfs
HDU 3394 Railway 双连通求块
3177 Redundant Paths 构造边双连通,利用度数去求
3352 Road Construction 构造边双连通,利用度数去求
1515 Street Directions 无向图改有向图,双连通内部肯定都能改,桥不能改
1438 One-way Traffic 混合图改有向图(这题的数据貌似有点问题)
点双连通
点双连通,求出来个,连接的是割点,注意一个割点可能属于不同的点-双连通分量。割点定义为:去掉这个点后,图将不连通
模板:
#include <cstdio> #include <cstring> #include <vector> #include <algorithm> #include <stack> using namespace std; const int N = 1005; const int M = 2000005; int n, m; struct Edge { int u, v; Edge() {} Edge(int u, int v) { this->u = u; this->v = v; } } edge[M]; int first[N], next[M], en; void add_edge(int u, int v) { edge[en] = Edge(u, v); next[en] = first[u]; first[u] = en++; } void init() { en = 0; memset(first, -1, sizeof(first)); } int pre[N], dfn[N], bccno[N], dfs_clock, bccn; bool iscut[N]; stack<Edge> S; vector<int> bcc[N]; void dfs_bcc(int u, int fa) { dfn[u] = pre[u] = ++dfs_clock; int child = 0; for (int i = first[u]; i + 1; i = next[i]) { int v = edge[i].v; if (fa == v) continue; if (!pre[v]) { S.push(edge[i]); child++; dfs_bcc(v, u); dfn[u] = min(dfn[u], dfn[v]); if (dfn[v] >= pre[u]) { iscut[u] = true; bccn++; bcc[bccn].clear(); while (1) { Edge x = S.top(); S.pop(); if (bccno[x.u] != bccn) {bcc[bccn].push_back(x.u); bccno[x.u] = bccn;} if (bccno[x.v] != bccn) {bcc[bccn].push_back(x.v); bccno[x.v] = bccn;} if (x.u == u && x.v == v) break; } } } else if (pre[v] < pre[u] && v != fa) { S.push(edge[i]); dfn[u] = min(dfn[u], pre[v]); } } if (fa == 0 && child == 1) iscut[u] = 0; } void find_bcc() { memset(pre, 0, sizeof(pre)); memset(bccno, 0, sizeof(bccno)); memset(iscut, false, sizeof(iscut)); dfs_clock = bccn = 0; for (int i = 1; i <= n; i++) if (!pre[i]) dfs_bcc(i, 0); }
POJ 2942 Knights of the Round Table 点双连通经典题,利用点双连通和二染色去做
UVA 1108 Mining Your Own Business 点双连通分量+计数