费用流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;
}
posted @ 2025-02-26 11:00  流氓兔LMT  阅读(40)  评论(0)    收藏  举报