题意:有C头奶牛,K个挤奶站,每个挤奶器最多服务M头奶牛,奶牛和奶牛、奶牛和挤奶站、挤奶站和挤奶站之间都存在一定的距离。现在问满足所有的奶牛都能够被挤奶器服务到的情况下,行走距离的最远的奶牛的至少要走多远。题目给的邻接矩阵是K个挤奶站与C个奶牛的距离矩阵,其中0为不可达的意思。
刚刷网络流,第一次遇到这样题目,题意我就看了半天才懂。。此题需要将题给条件转化,最后利用二分枚举距离,将每次情况建立一个新的图再网络流得解。
思路: 需要首先用Floyd将各个站与奶牛的最短距离得出,然后利用二分,左边界=0,右边界=题给每条路最大权值*最大可能走的路数=200*(K+C)。
然后将每次枚举的mid比较图中的边权,因为要枚举的是最大距离(的最小值,但最大距离的性质肯定还是有的,即大于等于其他边),所以边权<=mid,那些大于mid的边就当作该情况下不用走的,即可忽略。
将K与C以此建立网络流,并且设一个超级源点S与超级汇点T,S指向所有挤奶站K切边权为题给容量M,所有奶牛流向T边权为1。若最大流结果等于C说明该次枚举情况符合,便继续缩小枚举范围,若最大流结果小于C,说明边权限制过小则要增大枚举范围。一直反复枚举则得结果。
(代码转自https://www.cnblogs.com/Lyush/archive/2013/04/30/3052077.html)
1 #include <cstdlib> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 int K, C, M; // K个挤奶器,C头奶牛,每个挤奶器最多M头奶牛共享 9 int N; 10 int mp[250][250]; 11 12 struct Edge { 13 int v, c, next; 14 }; 15 16 Edge e[100000]; 17 int idx, head[250]; 18 int lv[250]; 19 int front, tail, que[250]; 20 const int SS = 0, TT = 248; 21 const int INF = 0x3fffffff; 22 23 void insert(int a, int b, int c) { 24 e[idx].v = b, e[idx].c = c; 25 e[idx].next = head[a]; 26 head[a] = idx++; 27 } 28 29 void floyd() { // 求出任意两点之间的最短路 30 for (int k = 1; k <= N; ++k) { 31 for (int i = 1; i <= N; ++i) { 32 if (mp[i][k] == INF || i == k) continue; 33 for (int j = 1; j <= N; ++j) { 34 if (mp[k][j] == INF || j == k) continue; 35 mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]); 36 } 37 } 38 } 39 } 40 41 void build(int threshold) { // 阀值 42 idx = 0; 43 memset(head, 0xff, sizeof (head)); 44 for (int i = 1; i <= K; ++i) { 45 insert(SS, i, M); 46 insert(i, SS, 0); 47 for (int j = K+1; j <= N; ++j) { 48 if (mp[i][j] <= threshold) { 49 insert(i, j, 1); 50 insert(j, i, 0); 51 } 52 } 53 } 54 for (int i = K+1; i <= N; ++i) { 55 insert(i, TT, 1); 56 insert(TT, i, 0); 57 } 58 } 59 60 bool bfs() { 61 front = tail = 0; 62 memset(lv, 0xff, sizeof (lv)); 63 lv[SS] = 0; 64 que[tail++] = SS; 65 while (front != tail) { 66 // printf("front = %d, tail = %d\n", front, tail); 67 int u = que[front++]; 68 for (int i = head[u]; i != -1; i = e[i].next) { 69 if (!(~lv[e[i].v]) && e[i].c) { 70 lv[e[i].v] = lv[u] + 1; 71 if (e[i].v == TT) return true; 72 que[tail++] = e[i].v; 73 } 74 } 75 } 76 return ~lv[TT]; 77 } 78 79 int dfs(int u, int sup) { 80 if (u == TT) return sup; 81 int tf = 0, f; 82 for (int i = head[u]; i != -1; i = e[i].next) { 83 if (lv[u]+1==lv[e[i].v] && e[i].c && (f=dfs(e[i].v, min(e[i].c, sup-tf)))) { 84 tf += f; 85 e[i].c -= f, e[i^1].c += f; 86 if (tf == sup) return sup; 87 } 88 } 89 if (!tf) lv[u] = -1; 90 return tf; 91 } 92 93 int dinic() { 94 int ret = 0; 95 while (bfs()) { 96 ret += dfs(SS, INF); 97 } 98 return ret; 99 } 100 101 int bsearch(int l, int r) { 102 int mid, ret; 103 while (l <= r) { 104 mid = (l + r) >> 1; 105 if (build(mid), dinic() == C) { 106 ret = mid; 107 r = mid - 1; 108 } else { 109 l = mid + 1; 110 } 111 } 112 return ret; 113 } 114 115 int main() { 116 while (scanf("%d %d %d", &K, &C, &M) != EOF) { 117 N = K+C; 118 memset(mp, 0, sizeof (mp)); 119 for (int i = 1; i <= N; ++i) { 120 for (int j = 1; j <= N; ++j) { 121 scanf("%d", &mp[i][j]); 122 if (!mp[i][j]) mp[i][j] = INF; 123 } 124 } 125 floyd(); 126 printf("%d\n", bsearch(1, 1000000)); 127 } 128 return 0; 129 }