1,介绍
就是边权还多了个单位费用,要你求所有最大流中花费费用最小的一个,其实说白了就是最大流+最短路
考虑到有负权边,我们一般是ek+spfa
为什么ek?遗憾的是,目前还未实现最小费用同时多路增广
2,模板题
对于ek的更改并不大,直接模板介绍
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 100;
int n, m, s, t;
int num;
int cost[N];
int pre[N];
ll dis[N];
bool vis[N];
int head[N<<1];//建立反向边,空间2倍
ll ans1, ans2;
struct node
{
ll to, next, w, c;
} edge[N<<1];//建立反向边,空间2倍
void add(ll u, ll v, ll w, ll c)
{
edge[++num].next = head[u];
edge[num].to = v;
edge[num].w = w;
edge[num].c = c;
head[u] = num;
edge[++num].next = head[v];
edge[num].w = 0; //反向边还是边权0
edge[num].c = -c; //注意,反向边费用为负值(因为后悔嘛)
edge[num].to = u;
head[v] = num;
}
bool bfs()
{
memset(vis, 0, sizeof(vis));
memset(cost, 0x3f, sizeof(cost)); //初始费用无穷
cost[s] = 0; //起点费用为0
vis[s] = 1;
dis[s] = INF;
queue<int>q;
q.push(s);
while (!q.empty())
{
int x = q.front();
q.pop();
vis[x] = 0; //spfa进来就标记为没有访问过
for (int i = head[x]; i; i = edge[i].next)
{
if (!edge[i].w)continue; //边权0,过
int v = edge[i].to;
if (cost[v] > cost[x] + edge[i].c)
{
pre[v] = i; //记录前驱
cost[v] = cost[x] + edge[i].c; //注意,比的是费用,不是边权
dis[v] = min(dis[x], edge[i].w); //储存该增广路上最小容量
if (!vis[v])vis[v] = 1, q.push(v); //spfa,既然我来了,没存过我就要进
}
}
}
return cost[t] != INF; //t的费用被改过,就是找到一条增广路
}
void update()
{
int v = t;
while (v != s)
{
int tmp = pre[v];
edge[tmp].w -= dis[t];
edge[tmp ^ 1].w += dis[t];
v = edge[tmp ^ 1].to;
}
ans1 += dis[t];
ans2 += dis[t] * cost[t];
}
int main()
{
cin >> n >> m >> s >> t;
num = 1, ans1 = 0, ans2 = 0;
ll u, v, w, c;
for (int i = 1; i <= m; ++i)
{
cin >> u >> v >> w >> c;
add(u, v, w, c);
}
while (bfs())update();
cout << ans1 << ' ' << ans2 << endl;
return 0;
}