最小费用最大流

题目描述

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

输入输出格式

输入格式:

第一行包含四个正整数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

(BYX:最后两个点改成了1200ms)

数据规模:

对于30%的数据:N<=10,M<=10

对于70%的数据:N<=1000,M<=1000

对于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。


首先这里给出的费用是单位流量的费用,这样最小费用就可以求出来了。

通俗的说,最小费用最大流其实就是最大流算法+Bellman-Ford算法,求最大流的同时,维护它的最短路径。

这里有几个要注意的点:

最大流的求法和原算法不变,直接加上就行了,最小费用也就可以得到是 最大流量 * 最小路径。

然后存储边的时候要把两边存在相邻(如0(0),1(1)    2(10),3(11) 等)的位置,这样就可以通过 ^1 来实现互相查询。

另外反向边的权值应为原边的相反数(走反向边相当于回溯,把原来走的边倒走回来)

最大费用直接把边去相反数即可转换为最小费用

#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 5000;
const int INF = 1E9;
typedef long long LL;
typedef double DB;
inline int get(){
	char c;
	while((c = getchar()) < '0' || c > '9');
	int cnt = c - '0';
	while((c = getchar()) >= '0' && c <= '9') cnt = cnt * 10 + c - '0';
	return cnt;
}
int N,M,S,T;
struct edge{
	int from,to,f,w;
	edge(int u,int v,int f,int w):from(u),to(v),f(f),w(w){}
}; 
vector e;
vector g[MAXN + 10];
int a[MAXN + 10];
int dis[MAXN + 10];
int pa[MAXN + 10];
bool est[MAXN + 10];
LL minv,maxf;
inline void mvmf(int Sat,int End){
	while(1){
		memset(a,0,sizeof(a));
		memset(dis,127,sizeof(dis));
		memset(est,false,sizeof(est));
		queue q;
		q.push(Sat);
		dis[Sat] = 0; a[Sat] = INF; est[Sat] = true;
		while(!q.empty()){
			int f = q.front(); q.pop(); est[f] = false;
			for(int i = 0; i < g[f].size(); i ++){
				edge k = e[g[f][i]];
				if(/*!a[k.to] &&*/ k.f > 0 && dis[k.from] + k.w < dis[k.to]){
					a[k.to] = min(a[k.from],k.f);
					dis[k.to] = dis[k.from] + k.w;
					pa[k.to] = g[f][i];
					if(!est[k.to]){
						q.push(k.to);
						est[k.to] = true;
					}
				}
			}
		}
		if(!a[End]) break;
		for(int i = End; i != Sat; i = e[pa[i]].from){
			e[pa[i]].f -= a[End];
			e[pa[i] ^ 1].f += a[End]; 
		}
		minv += (LL)dis[End] * (LL)a[End]; //
		maxf += a[End];
	}
	return;
}
int main(){
	#ifdef lwy
		freopen("1.txt","r",stdin);
/*	#else
		freopen(".in","r",stdin);
		freopen(".out","w",stdout);*/
	#endif
	N = get(); M = get(); S = get(); T = get();
	for(int i = 1; i <= M; i ++){
		int u,v,f,w;
		u = get(); v = get(); f = get(); w = get();
		e.push_back(edge(u,v,f,w));// u,v
		e.push_back(edge(v,u,0,-w)); // v,u   w -> -w
		int m = e.size();
		g[u].push_back(m - 2);
		g[v].push_back(m - 1);
	}
	minv = 0;
	mvmf(S,T);
	printf("%d %d",maxf,minv);
	return 0;
}




你可能感兴趣的:(模板,网络流)