POJ-2112 Optimal Milking 最短路+二分构图+网络流
题意:有C头奶牛,K个挤奶站,每个挤奶器最多服务M头奶牛,奶牛和奶牛、奶牛和挤奶站、挤奶站和挤奶站之间都存在一定的距离。现在问满足所有的奶牛都能够被挤奶器服务到的情况下,行走距离的最远的奶牛的至少要走多远。
解法:又是一个求最大中的最小问题,很容易想到用二分枚举来得出正确的答案。首先对整个图做一个floyd,求出两两之间的最短路,然后再枚举一个最大距离值进行构边,每次询问是否能够全部奶牛都能够被匹配到。注意:距离为0是当作INF处理,否则在floyd取min的时候要特判。
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int K, C, M; // K个挤奶器,C头奶牛,每个挤奶器最多M头奶牛共享 int N; int mp[250][250]; struct Edge { int v, c, next; }; Edge e[100000]; int idx, head[250]; int lv[250]; int front, tail, que[250]; const int SS = 0, TT = 248; const int INF = 0x3fffffff; void insert(int a, int b, int c) { e[idx].v = b, e[idx].c = c; e[idx].next = head[a]; head[a] = idx++; } void floyd() { // 求出任意两点之间的最短路 for (int k = 1; k <= N; ++k) { for (int i = 1; i <= N; ++i) { if (mp[i][k] == INF || i == k) continue; for (int j = 1; j <= N; ++j) { if (mp[k][j] == INF || j == k) continue; mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]); } } } } void build(int threshold) { // 阀值 idx = 0; memset(head, 0xff, sizeof (head)); for (int i = 1; i <= K; ++i) { insert(SS, i, M); insert(i, SS, 0); for (int j = K+1; j <= N; ++j) { if (mp[i][j] <= threshold) { insert(i, j, 1); insert(j, i, 0); } } } for (int i = K+1; i <= N; ++i) { insert(i, TT, 1); insert(TT, i, 0); } } bool bfs() { front = tail = 0; memset(lv, 0xff, sizeof (lv)); lv[SS] = 0; que[tail++] = SS; while (front != tail) { // printf("front = %d, tail = %d\n", front, tail); int u = que[front++]; for (int i = head[u]; i != -1; i = e[i].next) { if (!(~lv[e[i].v]) && e[i].c) { lv[e[i].v] = lv[u] + 1; if (e[i].v == TT) return true; que[tail++] = e[i].v; } } } return ~lv[TT]; } int dfs(int u, int sup) { if (u == TT) return sup; int tf = 0, f; for (int i = head[u]; i != -1; i = e[i].next) { if (lv[u]+1==lv[e[i].v] && e[i].c && (f=dfs(e[i].v, min(e[i].c, sup-tf)))) { tf += f; e[i].c -= f, e[i^1].c += f; if (tf == sup) return sup; } } if (!tf) lv[u] = -1; return tf; } int dinic() { int ret = 0; while (bfs()) { ret += dfs(SS, INF); } return ret; } int bsearch(int l, int r) { int mid, ret; while (l <= r) { mid = (l + r) >> 1; if (build(mid), dinic() == C) { ret = mid; r = mid - 1; } else { l = mid + 1; } } return ret; } int main() { while (scanf("%d %d %d", &K, &C, &M) != EOF) { N = K+C; memset(mp, 0, sizeof (mp)); for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { scanf("%d", &mp[i][j]); if (!mp[i][j]) mp[i][j] = INF; } } floyd(); printf("%d\n", bsearch(1, 1000000)); } return 0; }