【模板】最小费用最大流(增广路)(模板题:洛谷P3381)

题目描述

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

输入输出格式

输入格式:

第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。

接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。

输出格式:

一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。

输入输出样例

输入样例#1:
4 5 4 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5
输出样例#1:
50 280







说明

时空限制:1000ms,128M

数据规模:对于100%的数据:N<=5000,M<=50000

样例说明:

如图,最优方案如下:

第一条流为4-->3,流量为20,费用为3*20=60。

第二条流为4-->2-->3,流量为20,费用为(2+1)*20=60。

第三条流为4-->2-->1-->3,流量为10,费用为(2+9+5)*10=160。

故最大流量为50,在此状况下最小费用为60+60+160=280。

故输出50 280。




%:pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int MAXN=5010,MAXM=50010,INF=1e9;

struct XY{int to,pre,cost,cap;}e[2*MAXM];
struct XX{int pre,f,dis;bool b;}v[MAXN];

int n,m,s,t,sz=1,MaxFlow,MinCost,xx,yy,cc,ww;
int las[MAXN],xb[MAXN]; 

void add(int a,int b,int c,int z){
	++sz;e[sz].to=b;e[sz].cap=c;e[sz].cost=z;
	e[sz].pre=las[a];las[a]=sz;
}

int BFS(int s,int t){
	queue<int> Q;
	for (int i=0;i<=n;++i)
		v[i].dis=INF,v[i].b=false,v[i].pre=-1;
	v[s].b=1;v[s].dis=v[s].pre=0;v[s].f=INF;
	Q.push(s);
	while (!Q.empty()){
		int tmp=Q.front();v[tmp].b=false;Q.pop();
		for (int i=las[tmp];i;i=e[i].pre){
			int u=e[i].to;
			if (e[i].cap>0&&v[u].dis>v[tmp].dis+e[i].cost){
				v[u].dis=v[tmp].dis+e[i].cost;
				v[u].pre=tmp;xb[u]=i;
				v[u].f=min(v[tmp].f,e[i].cap);
				if (!v[u].b) v[u].b=1,Q.push(u);
			}
		}
	}
	if (v[t].dis>=INF) return 0;return 1;
}

void MinCost_MaxFlow(int s,int t){
	while (BFS(s,t)){
		int k=t;
		while (k!=s){
			e[xb[k]].cap-=v[t].f;e[xb[k]^1].cap+=v[t].f;
			k=v[k].pre;
		}
		MaxFlow+=v[t].f;MinCost+=v[t].f*v[t].dis;
	}
}


int main(){
	scanf("%d %d %d %d",&n,&m,&s,&t);
	for (int i=1;i<=m;++i){
		scanf("%d%d%d%d",&xx,&yy,&cc,&ww);
		add(xx,yy,cc,ww);add(yy,xx,0,-ww);
	}
	MinCost_MaxFlow(s,t);
	printf("%d %d",MaxFlow,MinCost);
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值