#include <iostream>
using namespace std;
#define MAXN 110
int graph[MAXN][MAXN];
int v[MAXN]; //i为结点初始编号, v[i]为结点当前编号, 便于删除结点并使序号始终连续
int wage[MAXN]; //该点加入之前集合中的所有顶点到该点的边权之和
bool mark[MAXN]; //标记顶点是否加入集合
int stoer_wagner(int n) {
int mincut = -1;
for (int i = 0; i < n; i++)
v[i] = i; //初始结点编号为自己
while (n > 1) { //(最初n) - 1轮
for (int i = 0; i < n; i++) {
wage[v[i]] = 0;
mark[v[i]] = false;
}
int pre = 0; //前一个加入集合的结点, 每次都从0开始
mark[v[pre]] = true; //结点0加入集合
for (int i = 1; i < n; i++) { //(当前n) - 1轮
int maxWageP = -1;
for (int j = 1; j < n; j++) { //根据前一个加入集合的结点更新wage, 并找到最大wage的点
if (mark[v[j]]) //j只用来遍历所有结点, 实际使用结点都需套上v, v[j]才是与graph对应的结点编号
continue;
wage[v[j]] += graph[v[pre]][v[j]]; //若没有边则加0, 不影响
if (maxWageP == -1 || wage[v[maxWageP]] < wage[v[j]])
maxWageP = j;
}
mark[v[maxWageP]] = true; //wage最大的结点加入集合
if (i == n - 1) { //最后一个加入集合的结点, 即T结点, 更新最小割
if (mincut == -1 || wage[v[maxWageP]] < mincut)
mincut = wage[v[maxWageP]];
//将T点contract到S结点上,然后删除T, T即v[maxWageP], S即pre
for (int j = 0; j < n; j++) {
graph[v[pre]][v[j]] += graph[v[maxWageP]][v[j]];
graph[v[j]][v[pre]] += graph[v[j]][v[maxWageP]];
}
n--; //删除点T后结点个数应减1
v[maxWageP] = v[n]; //下一轮结点应存储在v0到(n - 1), 最后一个结点与T交换编号达到删除T的目的
}
pre = maxWageP;
}
}
return mincut;
}
int main() {
int n, m;
while (cin >> n >> m) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
graph[i][j] = 0; //0代表没有边
}
}
while (m--) {
int x, y, c;
cin >> x >> y >> c;
graph[x][y] += c; //同一对顶点可能有多条边
graph[y][x] += c;
}
cout << stoer_wagner(n) << endl;
}
}
全局最小割stoer wagner c++模板
最新推荐文章于 2024-09-12 19:02:20 发布