2018.06.27最小费用最大流模板

最小费用最大流是指整个容量网络在保证流量最大的情况下使花费的费用最小,所以说与求最大流的思想有所差异。

我们知道,求最大流的思想是每次找一条增广路进行贪心直到贪不动为止,但是对于最小费用最大流这个问题来说,我们最后求得的一定是最大流,因此我们仍然每次贪心,只需保证费用最小即可。

于是我们使用SPFASPFASPFA而不是bfsbfsbfs来找最短增广路,我们在进行SPFASPFASPFA算法的同时用一个predpredpred的数组来记录对于当前节点uuu,从s−>us->us>u路径上离uuu最近的点,即uuu的前驱,最后从ttt开始沿着前驱修改边上的容量即可,这个时候我们并不需要使用dfsdfsdfs进行贪心,因为在进行若干次操作后一定会最大流

洛谷P3381最小费用最大流模板代码:

#include<bits/stdc++.h>
#define inf 0x7f
#define N 5005
#define M 50005
using namespace std;
int first[N],cnt=-1,n,m,s,t,d[N],pred[N],flow[N],in[N],pos[N];
struct Node{int v,next,c,w;}e[M<<1];
inline void add(int u,int v,int c,int w){
	e[++cnt].v=v;
	e[cnt].c=c;
	e[cnt].w=w;
	e[cnt].next=first[u];
	first[u]=cnt;
}
inline bool spfa(){
	queue<int>q;
	q.push(s);
	memset(d,inf,sizeof(d));
	memset(flow,inf,sizeof(flow));
	memset(in,0,sizeof(in));
	in[s]=1,pred[t]=-1,d[s]=0;
	while(!q.empty()){
		int x=q.front();
		q.pop(),in[x]=0;
		for(int i=first[x];i!=-1;i=e[i].next){
			int v=e[i].v;
			if(e[i].c>0&&d[v]>d[x]+e[i].w){
				d[v]=d[x]+e[i].w;
				pred[v]=x;
				pos[v]=i;
				flow[v]=min(flow[x],e[i].c);
				if(!in[v]){
					in[v]=1;
					q.push(v);
				}
			}
		}
	}
	return pred[t]!=-1;
}
inline void solve(){
	int maxnf=0,maxnw=0;
	while(spfa()){
		maxnf+=flow[t];
		maxnw+=flow[t]*d[t];
		int pot=t;
		while(pot!=s){
			e[pos[pot]].c-=flow[t];
			e[pos[pot]^1].c+=flow[t];
			pot=pred[pot];
		}
	}
	printf("%d %d",maxnf,maxnw);
}
int main(){
	memset(first,-1,sizeof(first));
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1;i<=m;++i){
		int u,v,c,w;
		scanf("%d%d%d%d",&u,&v,&c,&w);
		add(u,v,c,w);
		add(v,u,0,-w);
	}
	solve();
	return 0;
}

转载于:https://www.cnblogs.com/ldxcaicai/p/9738577.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值