# 【模板】最小费用最大流

$Link$

# $Description$

## $Sample$$Input$

4 5 4 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5


## $Sample$$Output$

50 280


## $Train$$of$$Thought$

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

int h[10250], F[10250], last[10250], bol[10250];
int x, y, t, n, m, k, cost, start, end;
int Ans_cost, Ans_flow;

struct edge
{
int x, w, k, cost, h, other;
}wh[500250];
//x为从哪里来//w为到哪里去//k为先可以留多少水//cost为每一单位水流过此处应付的钱//h为下一条边//other为对应的正/反向边
void hw(int x, int y, int k, int cost)
{
wh[++t] = (edge){x, y, k, cost, h[x], t + 1}, h[x] = t;
wh[++t] = (edge){y, x, 0, -cost, h[y], t - 1}, h[y] = t;
//因为一开始没有流水，所以反向边的可流量为0
//因为反向边是倒流，所以原来的钱应该还回来，所以是负数
}

int SPFA()
{
memset(F, 0x7f,sizeof(F));
memset(bol, 0, sizeof(bol));
F[start] = 0;
queue<int>s;
bol[start] = 1;
s.push(start);
while(s.size())
{
int x = s.front();s.pop();
for(int i = h[x]; i; i = wh[i].h)
if(wh[i].k && F[wh[i].w] > F[x] + wh[i].cost)
{
F[wh[i].w] = F[x] + wh[i].cost;
last[wh[i].w] = i;//记录经过的路劲
if(!bol[wh[i].w])bol[wh[i].w] = 1, s.push(wh[i].w);
}
bol[x] = 0;
}
if(F[end] < F[5200])return 1;
else return 0;
}

void init()
{
int l = end, maxx = 1e9;
while(last[l])
{
maxx = min(maxx, wh[last[l]].k);//沿路找最小流量
l = wh[last[l]].x;
}
Ans_cost += F[end] * maxx, Ans_flow += maxx, l = end;//计算最小费用
while(last[l])
{
wh[last[l]].k -= maxx;
wh[wh[last[l]].other].k += maxx;//增广
l = wh[last[l]].x;
}
}
int main()
{
scanf("%d%d", &n, &m);
scanf("%d%d", &start, &end);
for(int i = 1; i <= m; ++i)
{
scanf("%d%d%d%d", &x, &y, &k, &cost);
hw(x, y, k, cost);//建边
}
while(SPFA())init();//用SPFA寻找增广路
printf("%d %d", Ans_flow, Ans_cost);
return 0;
}


©️2019 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客