费用流E-K
费用流
- 给定一个网络G = (V,E), 每条边有容量限制c(u,v), 还有单位
流量的费用w(u,v)。 - 当(u,v)的流量为f(u,v)时. 需要花费f(u,v) × w(u,v)的费用。
- 该网络中总花费最小的最大流称为最小费用最大流,总花费最大
的最大流称为最大费用最大流,二者合称费用流模型,即在最大流
的前提下考虑费用的最值。
- 一个网络的最大流是唯一的,不同路径有不同的费用。
- 我们用 w f/c 表示边的边权 流量/容量。
EK算法
- 在EK算法求解最大流的基础上,把"用BFS寻找一条增广路"改为用spfa寻找一条单位费用之和最小的增广路”(即把w(u,v)当做边权,在残留网上求最短路),即可求出最小费用最大流。
- 为了退流,反向边的初始容量为0,反向边的容量每次 +f
- 为了退费。 反向边的初始费用为-W, 走反向边的花费 +fx(-w)
注意:如果图上存在单位费用为负的圈 (负环)。无法求出该网络的最小费用最大流。此时需要先使用消圈算法消去图上的负圈。
板子
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int head[N],to[N],nxt[N],w[N],f[N];//w费用,f可流流量
int tot=1;
void add(int a,int b,int c,int d)
{
nxt[++tot]=head[a],head[a]=tot,to[tot]=b,f[tot]=c,w[tot]=d;
swap(a,b),c=0,d=-d;
nxt[++tot]=head[a],head[a]=tot,to[tot]=b,f[tot]=c,w[tot]=d;
}
int dis[N],pre[N],vis[N];
int mf[N];//流量
int S,T;
bool spfa()
{
memset(dis,0x3f,sizeof(dis));
memset(mf,0,sizeof(mf));
queue<int> q;
q.push(S);
dis[S]=0;
mf[S]=1e7;
vis[S]=1;
while(q.size())
{
int u=q.front();
vis[u]=0;
q.pop();
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
int ww=w[i];
if(dis[v]>dis[u]+ww&&f[i])
{
dis[v]=dis[u]+ww;
mf[v]=min(mf[v],f[i]);
pre[v]=i;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
return mf[T]>0;
}
void E_K()
{
int flow=0,cost=0;
while(spfa())
{
int v=T;
while(v!=S)
{
int i=pre[v];//i当前点
f[i]-=mf[T];
f[i^1]+=mf[T];
v=to[i^1];//上一个点
}
}
flow+=mf[T];
cost+=mf[T]*dis[T];
}
int main()
{
return 0;
}
本文来自博客园,作者:流氓兔LMT,转载请注明原文链接:https://www.cnblogs.com/-include-lmt/p/18738020

浙公网安备 33010602011771号