概念
割点:给定无向联通图
割边:给定无向联通图
考虑特殊的图——树的割点与割边:
- 树中度大于
的节点都是割点 - 树中任意一条边都是割边
如果树加上一条边之后就变成了环,而环上的边一定不是割边,环上的节点不一定不是割点。这就启发我们对图进行深度优先遍历,求出图的一颗搜索树,然后加边考虑环,根据搜索树求出图中的割点与割边。
割边
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 2e5 + 10;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], num;
bool bridge[M];
int n, m;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void tarjan(int x, int in_edge) {
dfn[x] = low[x] = ++num;
for (int i = h[x]; i != -1; i = ne[i]) {
int y = e[i];
if (!dfn[y]) {
tarjan(y, i);
low[x] = min(low[x], low[y]);
if (low[y] > dfn[x]) bridge[i] = bridge[i ^ 1] = true;
} else if (i != (in_edge ^ 1)) {
low[x] = min(low[x], dfn[y]);
}
}
}
int main() {
cin >> n >> m;
memset(h, -1, sizeof h);
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
add(a, b), add(b, a);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) tarjan(i, 0);
}
for (int i = 0; i < idx; i += 2) {
if (bridge[i]) cout << e[i ^ 1] << ' ' << e[i] << endl;
}
return 0;
}割点
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 2e5 + 10;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], num;
bool cut[N];
int n, m, root;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void tarjan(int x) {
dfn[x] = low[x] = ++num;
int child = 0;
for (int i = h[x]; i != -1; i = ne[i]) {
int y = e[i];
if (!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
if (low[y] >= dfn[x]) {
child++;
if (x != root || child > 1) cut[x] = true;
}
} else low[x] = min(low[x], dfn[y]);
}
}
int main() {
cin >> n >> m;
memset(h, -1, sizeof h);
for (int i = 0; i < m; i++) {
int a, b; cin >> a >> b;
add(a, b), add(b, a);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) root = i, tarjan(i);
}
for (int i = 1; i <= n; i++) {
if (cut[i]) cout << i << " ";
}
return 0;
}