最小花费最大流-保证理解-java模板

假如你已经知道了什么是最大流了。
我们直到,从 源点 到 汇点 的 最大流,我们确信这个值是唯一的,一定有最大流的存在。
那么最小花费最大流也就是:

这个最大的值,可能有多个情况,从源点 经过了不同的路径到达的 汇点,纵使最后得到的最大流值相同。 仍然可能有 不同的路径,假如每个路径的代价还不同,这意味着,我们一边要找最大流,一边还要确保我们走的路径代价要尽可能低。这两个因素导致我们不确定该不该走这一个边,感觉好麻烦。。。

不用着急。

这时候,我们先不想这个问题,我们考虑简简单单的最短路问题。

想必你写过最短路, 我们从spfa这个算法入手。

我们把源点当做起点,汇点当做终点,请注意,我们把 边的单位代价当做边长,也就是 边的代价/边容量 而不是边的容量!, 先走一遍spfa ,ok,现在,是不是一定有 dis[] 数组了,对吗。别忘了,我们最短路最后就是得出一个dis数组来的。 这也意味着,我们有了一条最小路径了。( 我们在 更新dis[] 的时候,顺带更新一个pre 数组就行了, 用来记录最短路径的。。)。

好了,这时候我们要做一件最重要的事情,也就是算法的核心
我们找找这天路径上面,容量最小的那个边
真是妙,我们只用找这路上最小容量,必定就是 这个路径的最大流了。

然后 , 最小容量 x 路径长 , 这不就是这条路径的整个代价了嘛!

以此类推,通过更新边容量之后,在进行第二次,第三次,第四次,spfa ,直到找不到源点到汇点的最短路径了。

总结:

核心是,把一个边的  单位代价 ,当做路径长,跑一遍spfa。得到一个结果
然后把一些边的容量更新了( 一些边的容量变小), 再跑,,直到没到汇点的路径了。。

自己的代码:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.StringTokenizer;

// 
public class 最大流最小路径模板 {
	static class InputReader
	{
	    BufferedReader buf;
	    StringTokenizer tok;
	    InputReader()
	    {
	        buf = new BufferedReader(new InputStreamReader(System.in));
	    }
	    boolean hasNext()
	    {
	        while(tok == null || !tok.hasMoreElements()) 
	        {
	            try
	            {
	                tok = new StringTokenizer(buf.readLine());
	            } 
	            catch(Exception e) 
	            {
	                return false;
	            }
	        }
	        return true;
	    }
	    String next()
	    {
	        if(hasNext()) return tok.nextToken();
	        return null;
	    }
	    int nextInt()
	    {
	        return Integer.parseInt(next());
	    }
	    long nextLong()
	    {
	        return Long.parseLong(next());
	    }
	    double nextDouble()
	    {
	        return Double.parseDouble(next());
	    }
	    BigInteger nextBigInteger()
	    {
	        return new BigInteger(next());
	    }
	    BigDecimal nextBigDecimal()
	    {
	        return new BigDecimal(next());
	    }
	}
	static 	Queue<Integer> q;
	static int n,m,con,start,end;
	static int cost,minflow;
	static int[]head ,dis, vis,belong_e ,  pre;
	static class e{
		int u,v,next,w, cost;
	}static e[]es;
	static void add(int u,int v,int w, int cost) {
		if(es[con]==null) es[con]=new e();
		es[con].cost=cost;es[con].v=v;es[con].w=w;es[con].next=head[u];head[u]=con++;
	}
	//这个本质也是dfs
	//就是为了找一条从源点到汇点的最短路
	static boolean spfa() {
		for(int i=1;i<=n;i++) {
			dis[i]=0x3f3f3f3f;
			vis[i]=0;
		}
		dis[start]=0;vis[start]=1;
		q.clear();q.add(start);
		while(!q.isEmpty()) {
			int u=q.poll();
			vis[u]=0;
			for(int i=head[u];i!=-1;i=es[i].next) {									
				  int v=es[i].v;
				  if( es[i].w>0 &&  dis[v]> dis[u]+es[i].cost ) {
					  pre[v]=u;belong_e[v]=i;
					  dis[v]=dis[u]+es[i].cost;
					  if(vis[v]==0) {	
						  q.add(v);
						  vis[v]=1;
					  }
				  }
			}
		}
		return dis[end]<0x3f3f3f3f;
	}

	public static void main(String[] args) {
		InputReader  sc=new InputReader();
		head=new int[5005];
		belong_e=new int[150000];
		pre=new int[5005];
		dis=new int[5005];
		vis=new int[5005];
		es=new e[150005];
		q=new LinkedList<Integer>();
		n=sc.nextInt();
		m=sc.nextInt();
		start=sc.nextInt();
		end=sc.nextInt();
		
		Arrays.fill(head, -1);con=0;
		
		for(int i=0;i<m;i++) {
			int a=sc.nextInt();int b=sc.nextInt();int c=sc.nextInt(); int d=sc.nextInt();
			add(a,b,c,d); add(b,a,0,-d);
		}
		cost=0;
		minflow=0;
		while(spfa()) {
			int temp=0x3f3f3f3f;
			for(int i=end;i!=start;i=pre[i]) {
				temp=Math.min(temp, es[belong_e[i]].w);
			}
			cost+=dis[end]*temp;
			minflow+=temp;
			for(int i=end; i!=start; i=pre[i]) {
				es[belong_e[i]].w-=temp;
				es[belong_e[i] ^1 ].w+=temp;
			}
		}
		System.out.println(minflow+" "+cost);
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值