http://poj.org/problem?id=2112
题意:
给出K个挤奶的机器,C个奶牛,以及每个挤奶机器每天最多服务M头奶牛,给出他们的之间的距离。求奶牛到挤奶器处产奶,其满足小于等于M的情况下,最远距离的最小值。
思路:
不得不说这是一个很好的题目,首先我们看到的是机器每天工作量的限制,让我们联想到流的限制。我们首先二分枚举一个距离,然后建图源点s到挤奶器建边权值为M,奶牛到汇点e建边权值为1.然后枚举奶牛与挤奶器之间的距离,如果小于mid就建立一条权值为1的边,然后求最大流如果小于C继续增加,否则减小。 这里建图之前先用floyd求出任意两点之间的最短距离,这样保证枚举的任意两点距离最短。
//#pragma comment(linker,"/STACK:327680000,327680000") #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define inf 0x7f7f7f7f #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define ll long long #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x)int #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout); #define N 350 using namespace std; struct node { int v,w; int next; }g[N*N]; int head[N],ct; int mat[N][N]; int level[N]; int q[N*1000]; int K,C,M,n; void add(int u,int v,int w) { g[ct].v = v; g[ct].w = w; g[ct].next = head[u]; head[u] = ct++; g[ct].v = u; g[ct].w = 0; g[ct].next = head[v]; head[v] = ct++; } bool layer(int s,int e) { int i; CL(level,-1); queue<int>q; q.push(s); level[s] = 1; while (!q.empty()) { int u = q.front(); q.pop(); for (i = head[u]; i != -1; i = g[i].next) { int v = g[i].v; int w = g[i].w; if (w > 0 && level[v] == -1) { level[v] = level[u] + 1; if (v == e) return true; q.push(v); } } } return false; } int find(int s,int e) { int i; int top = 1,u; int ans = 0; while (top) { if (top == 1) u = s; else u = g[q[top - 1]].v; if (u == e) { int MIN = inf,pos = 0; for (i = 1; i <= top - 1; ++i) { if (MIN > g[q[i]].w) { MIN = g[q[i]].w; pos = i; } } for (i = 1; i <= top - 1; ++i) { g[q[i]].w -= MIN; g[q[i]^1].w += MIN; } ans += MIN; top = pos; } else { for (i = head[u]; i != -1; i = g[i].next) { int w = g[i].w; int v = g[i].v; if (level[v] == level[u] + 1 && w > 0) { q[top++] = i; break; } } if (i == -1) { top--; level[u] = -1; } } } return ans; } int dinic(int s,int e) { int ans = 0; while (layer(s,e)) ans += find(s,e); return ans; } void build(int s,int e,int mid) { int i,j; CL(head,-1); ct = 0; for (i = 1; i <= K; ++i) add(s,i,M); for (i = K + 1; i <= n; ++i) add(i,e,1); for (i = 1; i <= K; ++i) { for (j = K + 1; j <= n; ++j) { if (mat[i][j] <= mid) add(i,j,1); } } } void floyd() { int i,j,k; for (k = 1; k <= n; ++k) { for (i = 1; i <= n; ++i) { for (j = 1; j <= n; ++j) { if (mat[i][k] != inf && mat[k][j] != inf && mat[i][j] > mat[i][k] + mat[k][j]) { mat[i][j] = mat[i][k] + mat[k][j]; } } } } } int main() { //Read(); int i,j; while (~scanf("%d%d%d",&K,&C,&M)) { n = K + C; for (i = 1; i <= n; ++i) { for (j = 1; j <= n; ++j) { scanf("%d",&mat[i][j]); if (mat[i][j] == 0) mat[i][j] = inf; } } floyd(); int s = 0, e = n + 1; int l = 0; int r = 200*n; int res = 0; while (l <= r) { int mid = (l + r)/2; build(s,e,mid); int ans = dinic(s,e); // printf("%d %d %d %d\n",ans,l,r,mid); if (ans == C) { res = mid; r = mid - 1; } else l = mid + 1; } printf("%d\n",res); } return 0; }