学习笔记——费用流

费用流,也称最小/大费用最大流,在费用流问题中,每条边会的权值是个二元组(容量,费用),其中费用表示的是每流过一单位的水所耗费的费用,即一条边的总费用为流量×费用。 而通常,费用流问题会让你解决在满足最大流情况下的最小/大费用。

因为是求最小/最大费用,于是我们可以考虑用最短路算法(由于可能会有负权费用,所以推荐用SPFA)来找增广路,记录下路径,然后增广即可。

例题:【线性规划与网络流24题 17】运输问题

源点向每个仓库建边(容量:ai,费用:0),每个商店向汇点建边(容量:bi,费用:0),每个仓库向每个商店都建一条边(容量:,费用:ci,j),然后跑最小费用最大流即可。

对于最大费用最大流,可以将费用变成它的相反数,最后答案再取相反数即可。

code:

#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 100 + 5;
const int MAX_V = 200 + 5;
const int MAX_M = 30000 + 5;
const int inf = 1e9;
int Flow,Cost,dis[MAX_V],inq[MAX_V],pre[MAX_V];
int n,m,S,T,a[MAX_N],b[MAX_N],c[MAX_N][MAX_N];
int Last[MAX_V],End[MAX_M<<1],Next[MAX_M<<1],len[MAX_M<<1],cost[MAX_M<<1],tot;
inline void addedge(int x,int y,int z,int co){
	End[++tot]=y,Next[tot]=Last[x],Last[x]=tot,len[tot]=z,cost[tot]=co;
	End[++tot]=x,Next[tot]=Last[y],Last[y]=tot,len[tot]=0,cost[tot]=-co;
}
inline bool spfa(){
	for(int i=1;i<=T;i++) dis[i]=inf,pre[i]=0;
	dis[S]=0;
	queue<int> q;
	inq[S]=1;
	q.push(S);
	while(q.size()){
		int x=q.front();
		q.pop();
		inq[x]=0;
		for(int i=Last[x];i;i=Next[i]){
			int y=End[i];
			if(len[i] && dis[y]>dis[x]+cost[i]){
				dis[y]=dis[x]+cost[i];
				pre[y]=i;
				if(!inq[y]){
					q.push(y);
					inq[y]=1;
				}
			}
		}
	}
	int f=inf;
	if(dis[T]==inf) return false;
	for(int i=T;i!=S;i=End[pre[i]^1]) f=min(f,len[pre[i]]);
	for(int i=T;i!=S;i=End[pre[i]^1]) len[pre[i]]-=f,len[pre[i]^1]+=f;
	Flow+=f,Cost+=f*dis[T];
	return true;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=m;i++) scanf("%d",&b[i]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&c[i][j]);
	tot=1;S=n+m+1,T=S+1;
	for(int i=1;i<=n;i++) addedge(S,i,a[i],0);
	for(int i=1;i<=m;i++) addedge(i+n,T,b[i],0);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			addedge(i,j+n,inf,c[i][j]);
	while(spfa());
	printf("%d\n",Cost);
	tot=1;S=n+m+1,T=S+1;
	Flow=0,Cost=0;
	memset(Last,0,sizeof(Last));
	for(int i=1;i<=n;i++) addedge(S,i,a[i],0);
	for(int i=1;i<=m;i++) addedge(i+n,T,b[i],0);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			addedge(i,j+n,inf,-c[i][j]);
	while(spfa());
	printf("%d\n",-Cost);
	return 0;
}
posted @   Thermalrays  阅读(376)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示