感谢forwiat的博客帮助理解
几个关键点
1.增广路径的满足条件
(1)所有正向边f(u,v) < c(u,v)
(2)所有逆向边 f(u,v) > 0
2.更新 f和c, d是路径上最小的remain_capacity
正向边 f(u,v) = f(u,v)+d c(u,v) = c(u,v)-d
逆向边f(u,v) = f(u,v)-d c(u,v)不更新
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define inf 0x3f3f3f3f
#define maxn 20
using namespace std;
int capacity[maxn][maxn]; //路径上的最大容量
int flow[maxn][maxn]; //实际的流量
int book[maxn]; //标记一下哪些点已经找过了,后续就不再访问那个点了
int father[maxn]; //用来存放该节点的父节点是谁
typedef struct {
int point;
int MIN_remain_capcity;
}Node;
queue<Node> q;
//循环调用BFS知道没有找到一条增广路径,return的返回值是增加的流量
int findAugmentingPath(int start, int end, int n)
{
memset(book, 0, sizeof(book));
memset(father, -1, sizeof(father));
while(!q.empty()) {
q.pop();
}
Node firstPoint;
firstPoint.point=start;
firstPoint.MIN_remain_capcity=inf;
q.push(firstPoint);
Node front; //存放queue的第一个元素
while(!q.empty()) {
front = q.front();
q.pop();
for(int i=1;i<=n;i++) {
//判断两个点之间是否直接相连,且该点之前没有走过
if(!book[i] && capacity[front.point][i]!=inf) {
Node next;
next.point=i;
next.MIN_remain_capcity=front.MIN_remain_capcity;//把父节点的remain_capacity赋值给当前节点
if(capacity[front.point][i]>0) {//正向边的情况
if(flow[front.point][i] < capacity[front.point][i]) { //f(u,v) < c(u,v)
if(front.MIN_remain_capcity > capacity[front.point][i]) { //计算最小的remain_capacity
next.MIN_remain_capcity=capacity[front.point][i];
}
father[i]=front.point;//可以找到父节点,为了最后找汇点的时候进行remain_capacity的更新
book[i]=1;
q.push(next);
//如果找到汇点,则返回拿到的最小capacity,并且更新原有的capacity
if(i==end) {
cout<<"find"<<endl;
int p=i;
while(p!=-1) { //更新原来路径的remain_capacity和flow
cout<<p<<" ";
capacity[father[p]][p] -= next.MIN_remain_capcity; //更新remain_capacity
capacity[p][father[p]] = capacity[father[p]][p];
//之所以更新flow数组,是因为前面会比较flow跟capacity的大小
flow[father[p]][p] += next.MIN_remain_capcity; //f(u,v) = f(u,v)+d
flow[p][father[p]] = flow[father[p]][p];
p=father[p];
}
cout<<endl;
return next.MIN_remain_capcity;//返回最小的remain_capacity
}
}
}//逆向边的情况
else if(capacity[front.point][i]<0) { //这里不直接使用else的原因是还有=0的情况
if(flow[front.point][i] > 0) { //f(u,v) >0
if(front.MIN_remain_capcity > -capacity[front.point][i]) { //计算最小的remain_capacity
next.MIN_remain_capcity=-capacity[front.point][i]; //这里因为是负值,所以加个h负号把它变成正的
}
father[i]=front.point;//可以找到父节点,为了最后找汇点的时候进行remain_capacity的更新
book[i]=1;
q.push(next);
//如果找到汇点,则返回拿到的最小capacity,并且更新原有的capacity
if(i==end) {
cout<<"find"<<endl;
int p=i;
while(p!=-1) { //更新原来路径的remain_capacity和flow, 逆向边不更新remain_capacity
//之所以更新flow数组,是因为前面会比较flow跟capacity的大小
flow[father[p]][p] -= next.MIN_remain_capcity;
flow[p][father[p]] = flow[father[p]][p];
cout<<p<<" ";
p=father[p];
}
cout<<endl;
return next.MIN_remain_capcity;//返回最小的remain_capacity
}
}
}
}
}
}
return -1;
}
int main()
{
int n,m,front,to,weight;
int start, end; //start起点,end终点
cin>>n>>m;
cin>>start>>end;
for(int i=0;i<m;i++){
cin>>front>>to>>weight;
capacity[front][to]=weight;
capacity[to][front]=-weight;
}
int temp=findAugmentingPath(start, end, n);
int sum=0;
while(temp != -1){
sum += temp;
temp = findAugmentingPath(start, end, n);
}
cout<<sum<<endl;
return 0;
}
/*
5 6
1 5
1 2 4
1 3 6
2 3 2
2 4 3
3 5 4
4 5 5
*/