最小费用最大流 学习笔记&&Luogu P3381 【模板】最小费用最大流

题目描述

给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。

题目链接


思路

最大流是没有问题的,关键是同时保证最小费用,因此,就可以把每条边的费用视为距离,每次增广时用spfa代替bfs选取最小费用的增广路,这样跑一遍EK就可以了

据听说有神仙用dij跑最小费用最大流。。。可是我太弱了

犯的一些小问题:建反向边建错了两次(一次u、v写反,一次w忘取0)qwq

code

#include<bits/stdc++.h>
#define fex	for(int i=head[x];i!=-1;i=edge[i].next)
using namespace std;
const int MAXN=5e5+5,INF=0x3f3f3f3f;
struct node{
	int to,cost,w,next;
}edge[MAXN];
int cnt=-1,n,m,minc,maxf,s,t;
int pre[MAXN],from[MAXN],head[MAXN],dist[MAXN],nf[MAXN];
bool _in[MAXN];
queue<int > q;

void addedge(int from,int to,int w,int cost)
{
	edge[++cnt].cost=cost;
	edge[cnt].next=head[from];
	edge[cnt].to=to;
	edge[cnt].w=w;
	head[from]=cnt;
}

bool spfa()
{
	memset(dist,INF,sizeof(dist)),memset(_in,0,sizeof(_in));
	while(!q.empty()){
		q.pop();
	}
	q.push(s);
	dist[s]=0,_in[s]=1,nf[s]=INF;
	while(!q.empty()){
		int x=q.front();
//		cout<<x<<"spfa\n";
		q.pop();
		_in[x]=0;
		fex{
			int y=edge[i].to;
			if(edge[i].w>0&&edge[i].cost+dist[x]<dist[y]){
				dist[y]=dist[x]+edge[i].cost;
				nf[y]=min(nf[x],edge[i].w);
				from[y]=x;
				pre[y]=i;
				if(!_in[y]){
					_in[y]=1;
					q.push(y);
				}
			}
		}
	}
	return dist[t]!=INF;
}

void EK()
{
	while(spfa()){
		int x=t;
//		puts("EK");
		while(x!=s){
			int y=from[x],i=pre[x];
			edge[i].w-=nf[t];
			edge[i^1].w+=nf[t];
			x=y;
		}
		maxf+=nf[t];
		minc+=dist[t]*nf[t];
	}
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	memset(head,-1,sizeof(head));
	cin>>n>>m>>s>>t;
	for(int i=1;i<=m;i++){
		int u,v,w,f;
		cin>>u>>v>>w>>f;
		addedge(u,v,w,f);
		addedge(v,u,0,-f);
	}
	EK();
	cout<<maxf<<' '<<minc<<endl;
	return 0;
}

参考资料

posted @ 2019-09-15 15:57  zhu_chen  阅读(130)  评论(0编辑  收藏  举报