POJ 2112 - Optimal Milking
http://poj.org/problem?id=2112
概要
K 個の搾乳機と C 頭の牛がある. 各搾乳機は一日に M 頭の牛を処理できる.
どの牛もいずれかの搾乳機のところまで行かせるとき,牛が歩く必要のある最大の距離を最小化したい. そのときの距離を答える.
制約
- 1 <= K <= 30
- 1 <= C <= 200
- 1 <= M <= 15
解法
二分探索 + 最大流.
まず各ノード間の最短距離をワーシャルフロイドで求めておいて,最短距離が D 以下のエッジのみを使って条件を満たすように牛が移動できるかを判断して,D について二分探索.
条件を満たせるかどうかは,ソースから牛に1のエッジを張り,搾乳機からシンクに M の容量のエッジを張り,使えるエッジに無限大の容量を持たせたときの最大流が C 未満かどうかで判断できる.
poj/2112.cc1 #include <cstdio> 2 #include <limits> 3 #include <queue> 4 #include <algorithm> 5 using namespace std; 6 static const int MAX_N = 232; 7 8 int edmonds_karp(const int capacity[MAX_N][MAX_N], int N, int source, int sink)/*{{{*/ 9 { 10 static int flow[MAX_N][MAX_N]; 11 for (int i = 0; i < N; i++) { 12 fill_n(flow[i], N, 0); 13 } 14 int max_flow = 0; 15 16 while (true) { 17 static int parent[MAX_N]; 18 fill_n(parent, N, -1); 19 queue<int> q; 20 q.push(source); 21 22 while (!q.empty() && parent[sink] < 0) { 23 const int v = q.front(); 24 q.pop(); 25 26 for (int u = 0; u < N; u++) { 27 if (parent[u] < 0 && capacity[v][u] - flow[v][u] > 0) { 28 parent[u] = v; 29 if (u == sink) { 30 break; 31 } 32 q.push(u); 33 } 34 } 35 } 36 37 if (parent[sink] < 0) { 38 break; 39 } 40 41 int aug = numeric_limits<int>::max(); 42 for (int v = sink; v != source; v = parent[v]) { 43 const int u = parent[v]; 44 aug = min(aug, capacity[u][v] - flow[u][v]); 45 } 46 max_flow += aug; 47 for (int v = sink; v != source; v = parent[v]) { 48 const int u = parent[v]; 49 flow[u][v] += aug; 50 flow[v][u] -= aug; 51 } 52 } 53 54 return max_flow; 55 }/*}}}*/ 56 57 int main() 58 { 59 int K, C, M; 60 scanf("%d %d %d", &K, &C, &M); 61 const int N = K+C; 62 static int g[MAX_N][MAX_N]; 63 for (int i = 0; i < N; i++) { 64 for (int j = 0; j < N; j++) { 65 scanf("%d", &g[i][j]); 66 if (g[i][j] == 0) { 67 g[i][j] = numeric_limits<int>::max()/N; 68 } 69 } 70 } 71 72 for (int k = 0; k < N; k++) { 73 for (int i = 0; i < N; i++) { 74 for (int j = 0; j < N; j++) { 75 g[i][j] = min(g[i][j], g[i][k] + g[k][j]); 76 } 77 } 78 } 79 80 // binary search 81 int left = 0, right = 0; 82 for (int i = 0; i < K; i++) { 83 right = max(right, *max_element(g[i]+K, g[i]+K+C)); 84 } 85 while (left < right) { 86 const int mid = (left + right)/2; 87 static int capacity[MAX_N][MAX_N]; 88 // N: source 89 // N+1: sink 90 for (int i = 0; i < K; i++) { 91 capacity[N][i] = M; 92 for (int j = K; j < K+C; j++) { 93 capacity[j][N+1] = 1; 94 if (g[i][j] <= mid) { 95 capacity[i][j] = numeric_limits<int>::max(); 96 } else { 97 capacity[i][j] = 0; 98 } 99 } 100 } 101 102 const int max_flow = edmonds_karp(capacity, N+2, N, N+1); 103 if (max_flow < C) { 104 // ng. too short 105 left = mid+1; 106 } else { 107 // ok 108 right = mid; 109 } 110 } 111 printf("%d\n", left); 112 return 0; 113 }