POJ2516 Minimum Cost(網路流,最小費用最大流)
阿新 • • 發佈:2018-11-11
題目連結: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; } }