1. 程式人生 > >POJ2516 Minimum Cost(網路流,最小費用最大流)

POJ2516 Minimum Cost(網路流,最小費用最大流)

題目連結:http://poj.org/problem?id=2516

這道題有點嘔。

題目大概意思:

現在有n個店主,m個供應商,k個商品。

現在給你n*k的矩陣,表示每個店主對於每個商品的需求量。

然後給你m*k的矩陣,表示每個供應商每個物品的擁有量。

然後給你k個n*m的矩陣,表示每個商品在每個供應商和商人之間的消費。

最後求能否滿足所有店主都能得到滿足,如果可以輸出最小費用,否則輸出-1.

建圖就是對於每個商品都建圖。

  • 把源點和每一個供貨點相連,流量為當前供貨點的貨物存量,花費為0
  • 把店主和當前列舉的貨物相連,流量為當前店主需要的貨物量,花費為0
  • 然後再給每個供貨點和店主建邊,流量為供貨點的供貨量,花費為運送當前貨物的花費

這個樣子。

程式碼:

import java.util.*;
import java.io.*;
import java.math.*;
public class Main {
	static StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static PrintWriter out=new  PrintWriter(new OutputStreamWriter(System.out));
	static final int inf=1<<30;
	static int v,m,s,t,f;												//f是最大流量
	static ArrayList<Edge> g[];
	static int len;
	static int dist[];
	static int prevv[];
	static int preve[];
	static int h[];
	static void addEdge(int from,int to,int cap,int cost) {
		//System.out.println(from+" "+to+" "+cap+" "+cost);
		g[from].add(new Edge(to,cap,cost,g[to].size()));
		g[to].add(new Edge(from,0,-cost,g[from].size()-1));
	}
	static int min_cost(int s,int t) {
		int res=0;
		for(int i=0;i<=v;i++)
			h[i]=0;
		while(true) {
			for(int i=0;i<=v;i++)
				dist[i]=inf;
			dist[s]=0;
			PriorityQueue<P> list=new PriorityQueue<P>();
			list.offer(new P(0,s));
			while(!list.isEmpty()) {
				P p=list.poll();
				int v=p.b;
				if(dist[v]<p.a)continue;				//如果這個點更新過更小的距離
				for(int i=0;i<g[v].size();i++) {
					Edge e=g[v].get(i);
					if(e.cap>0&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to]) {
						dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
						prevv[e.to]=v;					//儲存前驅
						preve[e.to]=i;					//當點在前驅節點對應的位置
						list.add(new P(dist[e.to],e.to));
					}
				}
			}
			if(dist[t]==inf)
				break;
			for(int u=1;u<=v;u++)
				h[u]+=dist[u];
			int d=inf;
			for(int v=t;v!=s;v=prevv[v]) {
				d=Math.min(d,g[prevv[v]].get(preve[v]).cap);
			}
			f+=d;
			res+=d*h[t];
			for(int v=t;v!=s;v=prevv[v]) {
				Edge e=g[prevv[v]].get(preve[v]);
				e.cap-=d;
				g[v].get(e.rev).cap+=d;
			}
		}
		return res;
	}
	static void init() {
		h=new int[v+1];
		f=0;
		g=new ArrayList[v+1];
		for(int i=0;i<=v;i++) {
			g[i]=new ArrayList<Edge>();
		}
		dist=new int[v+1];
		prevv=new int[v+1];
		preve=new int[v+1];
	}
	public static void main(String[] args) throws Exception{
		Scanner sc=new Scanner(System.in);
		p:while(true) {
			//System.out.println("--");
			int a=getInt();
			int b=getInt();
			int c=getInt();							//店主,供貨點,商品個數
			if(a+b+c==0)break;
			v=a+b+2;
			int arr1[][]=new int[a+1][c+1];				//需求量
			for(int i=1;i<=a;i++)
				for(int j=1;j<=c;j++)
					arr1[i][j]=getInt();			//存貨量
			int arr2[][]=new int[b+1][c+1];
			for(int i=1;i<=b;i++)
				for(int j=1;j<=c;j++)
					arr2[i][j]=getInt();
			int arr3[][][]=new int[c+1][a+1][b+1];
			for(int i=1;i<=c;i++) 
				for(int j=1;j<=a;j++)
					for(int k=1;k<=b;k++)
						arr3[i][j][k]=getInt();
			int ans=0;
			for(int i=1;i<=c;i++) {
				s=0;
				v=2+a+b;
				t=v-1;
				init();
				int sum=0;
				for(int j=1;j<=a;j++) {				//店主和貨物
					addEdge(s,j,arr1[j][i],0);
					sum+=arr1[j][i];
				}
				for(int j=1;j<=b;j++) {				//供應商和匯點
					addEdge(a+j,t,arr2[j][i],0);
				}
				for(int j=1;j<=a;j++)
					for(int k=1;k<=b;k++)
						addEdge(j,a+k,arr2[k][i],arr3[i][j][k]);
				int d=min_cost(s,t);
				if(f!=sum) {
					System.out.println(-1);
					continue p;
				}
				//System.out.println(sum+" "+f);
				ans+=d;
				//return ;
			}
			System.out.println(ans);
		}
	}
	public static double getDouble() throws Exception {
		in.nextToken();
		return in.nval;
	}
	public static String getString() throws Exception{
		in.nextToken();
		return in.sval;
	}
	public static int getInt() throws Exception{
		in.nextToken();
		return (int)in.nval;
	}
}
class Edge{
	int to,cap,cost,rev;	//到達點,容量,消費,反向流量
	public Edge(int a,int b,int c,int d) {
		to=a;
		cap=b;
		cost=c;
		rev=d;
	}
}
class P implements Comparable{
	int a,b;
	public P(int a,int b) {
		this.a=a;
		this.b=b;
	}
	public int compareTo(Object o) {
		P p=(P)o;
		return this.a-p.a;
	}
}