题目描述
给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。
输入输出格式
输入格式:
输入文件的第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
输出格式:
输出文件一行包含两个整数,分别表示问题1和问题2的答案。
输入输出样例
输出样例#1:
13 19
题意:自个看。。。。
题解:
ans1毫无疑问就是求个最大流;ans2则是最小费用的K流(即花费最小费用流K的流量),
我们这里应该用跑完最大流的残留网络去接着对每一条边建立流量为INF,单位花费为w的边,
这样就可以保证花费是正确的。至于如何让流量为K,其实只需在起点或者终点做些改变就好,
比如在终点加条终点到终点+1的流量为K,花费为0的边,那么终点+1就成为了新的终点。
代码:
1 import java.util.Scanner; 2 import java.util.LinkedList; 3 import java.util.Queue; 4 5 6 class edge{ 7 int to; 8 int next; 9 int flow; 10 int w; 11 public edge(int to,int next,int flow,int w) { 12 super(); 13 this.to=to; 14 this.next=next; 15 this.flow=flow; 16 this.w=w; 17 } 18 } 19 20 public class Main { 21 22 public static final int maxn = (int) 1e3+10; 23 public static final int maxm = (int) 5e3+10; 24 public static final int INF = 0x3f3f3f3f; 25 static edge[] e = new edge[maxm<<2]; 26 static int[] head = new int[maxn]; 27 static int[] min_flow = new int [maxn]; 28 static int[] dis = new int[maxn]; 29 static int[] pre = new int[maxn]; 30 static int[] in = new int[maxn]; 31 static boolean[] vis = new boolean[maxn]; 32 static int tol,max_flow,min_cost; 33 private static Scanner scan; 34 35 public static void add(int start , int ed , int flow , int w) { 36 e[tol] = new edge(ed , head[start] , flow , w); 37 head[start]=tol++; 38 } 39 40 public static boolean spfa(int start,int ed) { 41 Queue<Integer>queue = new LinkedList<Integer>(); 42 for(int i = 0;i < maxn-1;i ++) { 43 min_flow[i] = dis[i] = INF; 44 pre[i] = 0; 45 vis[i] = false; 46 } 47 dis[start]=0; 48 queue.offer(start); 49 while(!queue.isEmpty()) { 50 int index = queue.poll(); 51 vis[index] = false; 52 for(int i = head[index];i != -1;i=e[i].next ) { 53 int to = e[i].to,w = e[i].w,f = e[i].flow; 54 if(dis[to] > dis[index] + w && f>0) { 55 56 dis[to] = dis[index] + w; 57 min_flow[to] = Math.min(min_flow[index], f); 58 pre[to] = index; 59 in[to] = i; 60 if(!vis[to]) { 61 queue.offer(to); 62 vis[to] = true; 63 } 64 } 65 } 66 } 67 return dis[ed] != INF; 68 } 69 70 public static void min_valAndMax_Flow(int start,int ed) { 71 max_flow = 0; 72 min_cost = 0; 73 while(spfa(start,ed)) { 74 max_flow += min_flow[ed]; 75 min_cost += dis[ed]*min_flow[ed]; 76 int to=ed; 77 while(pre[to] != 0) { 78 e[in[to]].flow -= min_flow[ed]; 79 e[in[to]^1].flow += min_flow[ed]; 80 to = pre[to]; 81 } 82 } 83 } 84 public static void clear() { 85 tol=0; 86 for(int i = 0;i < maxn-1;i ++) { 87 head[i] = -1; 88 } 89 } 90 public static void main(String[] args) { 91 scan = new Scanner(System.in); 92 93 clear(); 94 95 //定义点数N,边数M,要增加的流量K 96 int N,M,K,ans1=0,ans2=0; 97 98 //定义边起点s到终点t的数组和扩容需花费价钱w和流量f; 99 int[] s = new int[maxm]; 100 int[] t = new int[maxm]; 101 int[] w = new int[maxm]; 102 int[] f = new int[maxm]; 103 104 //输入点数,边数,要增加的流量 105 N = scan.nextInt(); 106 M = scan.nextInt(); 107 K = scan.nextInt(); 108 109 //存边,建图 110 for(int i = 0;i < M;i ++) { 111 s[i] = scan.nextInt(); 112 t[i] = scan.nextInt(); 113 f[i] = scan.nextInt(); 114 w[i] = scan.nextInt(); 115 add(s[i],t[i],f[i],0); 116 add(t[i],s[i],0,0); 117 } 118 119 min_valAndMax_Flow(1,N); 120 ans1 = max_flow; 121 //在残留图上接着建图 122 for(int i = 0;i < M;i ++) { 123 add(s[i],t[i],INF,w[i]); 124 add(t[i],s[i],0,0); 125 } 126 add(N,N+1,K,0); 127 add(N+1,N,0,0); 128 min_valAndMax_Flow(1,N+1); 129 ans2 = min_cost; 130 System.out.println(ans1+" "+ans2); 131 } 132 }