双连通总结
这类问题分为,边-双连通,点-双连通
边双连通
边双连通,求出来后,连接没一个双连通的分量的就是割边,因此可以缩点成一棵树,把问题转化为在树上搞,割边的定义为:去掉这条边后图将不连通
基本这类题都一个解法,求双连通分量,然后缩点成树,进行操作
或者就是直接要求割边,做跟割边相关的操作
模板:
#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 点双连通分量+计数