求使所有牛都可以被挤牛奶的条件下牛走的最长距离。
Floyd求出两两节点之间的最短路,然后二分距离。
构图:
将每一个milking machine与源点连接,边权为最大值m,每个cow与汇点连接,边权为1,然后根据二分的距离x,将g[i][j] < x的milking machine节点i与cow节点j连接,边权为1,其他的赋值为零。
最大流的结果是可以被挤奶的cow数量,判断是否等于总的cow总量即可。
#include <iostream> #include <cstring> #include <vector> #include <cstdio> #include <algorithm> using namespace std; #define N 240 #define INF 0x3f3f3f3f class Dinic { public: int n, s, t, l[N], c[N][N], e[N]; int flow(int maxf = INF) { int left = maxf; while (build()) left -= push(s, left); return maxf - left; } int push(int x, int f) { if (x == t) return f; int &y = e[x], sum = f; for (; y<n; y++) if (c[x][y] > 0 && l[x]+1==l[y]) { int cnt = push(y, min(sum, c[x][y])); c[x][y] -= cnt; c[y][x] += cnt; sum -= cnt; if (!sum) return f; } return f-sum; } bool build() { int m = 0; memset(l, -1, sizeof(l)); l[e[m++]=s] = 0; for (int i=0; i<m; i++) for (int y=0; y<n; y++) if (c[e[i]][y] > 0 && l[y]<0) l[e[m++]=y] = l[e[i]] + 1; memset(e, 0, sizeof(e)); return l[t] >= 0; } } net; int g[N][N], n, k, c, m; bool ok(int x) { memset(net.c, 0, sizeof(net.c)); net.s = 0, net.t = n + 1, net.n = n + 2; for (int i=1; i<=k; i++) net.c[0][i] = m; for (int i=k+1; i<=n; i++) net.c[i][net.t] = 1; for (int i=1; i<=k; i++) for (int j=k+1; j<=n; j++) if (g[i][j] <= x) net.c[i][j] = 1; else net.c[i][j] = 0; return net.flow() == c; } int main() { while (scanf("%d%d%d", &k, &c, &m) == 3) { n = k + c; for (int i=1; i<=n; i++) for (int j=1; j<=n; j++) { scanf(" %d", &g[i][j]); if (g[i][j] == 0 && i != j) g[i][j] = INF; } for (int p=1; p<=n; p++) for (int i=1; i<=n; i++) for (int j=1; j<=n; j++) g[i][j] = min(g[i][j], g[i][p] + g[p][j]); int l = 0, r = INF, mid, ans; while (l <= r) { mid = (l + r) >> 1; if (ok(mid)) { ans = mid; r = mid -1; } else l = mid + 1; } cout << ans << endl; } return 0; }