基本思路:
算法导论第26章
- 使用反平行边来模拟残存网络。
- 在残存网络中用广搜来寻找增广路径(用pre数组记录前驱结点)。
- 如找不到增广路径,已达到最大流,结束
- 如找到增广路径,最大流的增值为增广路径上的权值的最小值。
- 更新残存网络(从汇点通过前驱数组沿增广路径向前更新)。
- 更新最大流。
转步骤2。
example:
如下图找出从节点1到6的最大流。
输入:
6 9
1 2 16
2 4 12
4 6 20
5 6 4
3 5 14
1 3 13
3 2 4
4 3 9
5 4 7
1 6
输出:
23
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define MAXN 5000
using namespace std;
int n, S, T; //节点数,源点,汇点
vector<vector<int>> capacity;//残存网络的邻接矩阵
queue<int> qu; //广搜队列
int pre[MAXN], flow[MAXN]; //前驱数组;增广路径中的节点流
int find_augmenting_path(int s, int t) {
int index;
size_t i;
memset(pre, -1, n * sizeof(int));
while (!qu.empty()) qu.pop();
flow[s] = INF; //源点的流为INF
qu.push(s);
while (!qu.empty()) {
index = qu.front();
qu.pop();
if (index == t)break; //找到了一条增广路径
for (i = 0; i < n; ++i)
if (i != s && capacity[index][i] > 0 && pre[i] == -1) {//每个节点只遍历一次
pre[i] = index;
flow[i] = min(capacity[index][i], flow[index]);
qu.push(i);
}
}
if (pre[t] == -1)return 0;
return flow[t];
}
int maxflow(int s, int t) {
int sumflow = 0, increaseflow, v, prenode;
while (increaseflow = find_augmenting_path(s, t)){
v = t;
while (v != s) { //从汇点通过前驱数组向源点更新残存网络
prenode = pre[v];
capacity[prenode][v] -= increaseflow;
capacity[v][prenode] += increaseflow;
v = prenode;
}
sumflow += increaseflow;
}
return sumflow;
}
int main() {
size_t i, m;
int s, t, c;
while (cin >> n >> m ) {
capacity.assign(n, vector<int>(n, 0));
for (i = 0; i < m; ++i) {
cin >> s >> t >> c;
s--, t--;
capacity[s][t] = c;
}
cin >> S >> T;
cout << maxflow(S - 1, T - 1) << endl;
}
return 0;
}