无向图的割点和桥(模板)
求无向图的割点和桥的模板,大白书312页内容,用邻接表存储,为dfs添加时间戳这个概念,同时递归计算low函数的值
模板如下
int dfs(int u, int fa) {
int lowu = pre[u] = ++dfs_clock;
int child = 0;//子节点个数
for (int i = 0; i < g[u].size(); ++i) {
int v = g[u][i];
if (0 == pre[v]) {
++child;
int lowv = dfs(v, u);
lowu = min(lowu, lowv);
if (lowv >= pre[u]) {
iscut[u] = true;//割点
if (lowv > pre[u]) bridge.push_back(p(u, v));//桥
}
}
else if (pre[v] < pre[u] && v != fa) {//反向边(u,v)
lowu = min(lowu, pre[v]);
}
}
if (fa < 0 && child == 1) iscut[u] = false;//判断根结点
low[u] = lowu;
return lowu;
}
源程序
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> p;
const int maxn = 150;
const int maxm = 1050;
int n, m;//顶点数,边数
int dfs_clock;//dfs时间戳
int pre[maxn], low[maxn];//pre是记录时间戳的数组,low[u]表示u以及u的所有子孙中能连回祖先中最小的pre值
bool iscut[maxn];//顶点i是否为割点
vector<p> bridge;//存储图中的桥
vector<int> g[maxn];
void init() {
dfs_clock = 0;
memset(pre, 0, sizeof(pre));
memset(low, 0, sizeof(low));
memset(iscut, 0, sizeof(iscut));
bridge.clear();
for (int i = 0; i < maxn; ++i) g[i].clear();
}
int dfs(int u, int fa) {
int lowu = pre[u] = ++dfs_clock;
int child = 0;//子节点个数
for (int i = 0; i < g[u].size(); ++i) {
int v = g[u][i];
if (0 == pre[v]) {
++child;
int lowv = dfs(v, u);
lowu = min(lowu, lowv);
if (lowv >= pre[u]) {
iscut[u] = true;//割点
if (lowv > pre[u]) bridge.push_back(p(u, v));//桥
}
}
else if (pre[v] < pre[u] && v != fa) {//反向边(u,v)
lowu = min(lowu, pre[v]);
}
}
if (fa < 0 && child == 1) iscut[u] = false;//判断根结点
low[u] = lowu;
return lowu;
}
int main() {
while (scanf("%d%d", &n, &m) == 2) {
init();
for (int i = 1; i <= m; ++i) {
int from, to;
scanf("%d%d", &from, &to);
g[from].push_back(to);
g[to].push_back(from);
}
for (int i = 0; i < n; ++i) {//顶点编号从0开始
if (g[i].size() && 0 == pre[i]) dfs(i, -1);
}
cout << "割点:" << endl;
for (int i = 0; i < n; ++i) {
if (iscut[i]) cout << i << " ";
}
cout << endl << endl;
cout << "桥:" << endl;
for (int i = 0; i < bridge.size(); ++i) {
cout << bridge[i].first << " " << bridge[i].second << endl;
}
cout << endl;
}
return 0;
}