算法模板(8):网络流(3):费用流
费用流之算法模板
费用流:所有最大可行流中,费用的最小值/最大值
注意费用指的是这条边的单位费用,即为 边的流量 乘 边的费用.
2174. 费用流 - AcWing题库
- 题意:给定一个包含 n n n 个点 m m m 条边的有向图,并给定每条边的容量和费用,边的容量非负。图中可能存在重边和自环,保证费用不会存在负环。求从 S S S 到 T T T 的最大流,以及在流量最大时的最小费用。
- 每次沿着最短路增广,得到的费用是最小的。然后就是把 E K EK EK 算法中的 b f s bfs bfs 换成最短路即可,最短路中间加上对流量的更新即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 5010, M = 100010, INF = 1e8;
int h[N], e[M], ne[M], f[M], w[M], idx;
void add(int a, int b, int c, int d)
{
e[idx] = b, ne[idx] = h[a], f[idx] = c, w[idx] = d, h[a] = idx++;
e[idx] = a, ne[idx] = h[b], f[idx] = 0, w[idx] = -d, h[b] = idx++;
}
int n, m, S, T;
int incf[N], d[N], pre[N];
bool st[N];
bool spfa()
{
memset(d, 0x3f, sizeof d);
memset(incf, 0, sizeof incf);
queue<int> que;
d[S] = 0, incf[S] = INF;
que.push(S);
while(que.size())
{
int u = que.front(); que.pop();
st[u] = false;
for(int i = h[u]; i != -1; i = ne[i])
{
int v = e[i];
if(f[i] && d[v] > d[u] + w[i])
{
d[v] = d[u] + w[i];
pre[v] = i;
incf[v] = min(f[i], incf[u]);
if(!st[v])
{
que.push(v);
st[v] = true;
}
}
}
}
return incf[T] > 0;
}
void EK(int& flow, int& res)
{
flow = 0, res = 0;
while(spfa())
{
int t = incf[T];
flow += t, res += t * d[T];
for(int i = T; i != S; i = e[pre[i] ^ 1])
{
f[pre[i]] -= t, f[pre[i] ^ 1] += t;
}
}
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d%d%d", &n, &m, &S, &T);
for(int i = 1; i <= m; i++)
{
int a, b, c, d;
scanf("%d%d%d%d", &a, &b, &c, &d);
add(a, b, c, d);
}
int flow, res;
EK(flow, res);
printf("%d %d\n", flow, res);
return 0;
}s