POJ-2112 Optimal Milking
题目大意:
有k个挤奶器,在牧场里有c头奶牛,每个挤奶器可以满足m个奶牛,奶牛和挤奶器都可以看成是实体,现在给出两个实体之间的距离,如果没有路径相连,则为0,现在问你在所有方案里面,这c头奶牛需要走的最大距离的最小值。
解题思路:
floyd+最大流+二分
首先用floyd求出两个实体间的最短距离,然后二分枚举最大距离的最小值,用最大流来判断是否存在这个解。
因为涉及Floyd所以INF设置的值最好不要太大。千万不能是0x7fffffff
二分枚举答案的时候,r可以设置初值为1e4即可。
在使用最大流判断是否存在解的时候,要对每个解都重新建图。
建图需要一个超级源点,把所有的奶牛与源点相连,容量设置为1
把所有的挤奶器与汇点相连,容量为m
然后对于挤奶器和奶牛的距离不超过判断的解的距离的连边,容量设置为1
然后求解即可。
(建图部分可以直接看代码比较好)
代码:
#include <queue> #include <cstdio> #include <cstring> using namespace std; typedef struct node{ int v, cap, nxt; node(int a = 0, int b = 0, int c = 0){ v = a; cap = b; nxt = c; } }Edge; const int INF = 1e7; const int maxn = 300; const int maxm = 1e5; Edge edge[maxm]; int t, tot, K, C, M, N; int head[maxm], dis[maxn], d[maxn][maxn]; inline int Min(int a, int b){ return (a < b ? a : b); } void floyd(){ for(int k = 1; k <= N; ++k){ for(int i = 1; i <= N; ++i){ for(int j = 1; j <= N; ++j){ d[i][j] = Min(d[i][j], d[i][k] + d[k][j]); } } } } void add(int u, int v, int cap){ edge[tot] = Edge(v, cap, head[u]); head[u] = tot++; edge[tot] = Edge(u, 0, head[v]); head[v] = tot++; } int bfs(){ queue<int> q; while(!q.empty()) q.pop(); memset(dis, 0, sizeof(dis)); dis[0] = 1; q.push(0); while(!q.empty()) { int x = q.front(); q.pop(); if(x == t) break; for(int i = head[x]; ~i; i = edge[i].nxt){ Edge &e = edge[i]; if(e.cap && dis[e.v] == 0){ dis[e.v] = dis[x] + 1; q.push(e.v); } } } return dis[t]; } int dfs(int x, int f){ if(x == t) return f; int sum = 0; for(int i = head[x]; ~i; i = edge[i].nxt){ Edge &e = edge[i]; if(e.cap && dis[e.v] == dis[x] + 1){ int ret = dfs(e.v, Min(e.cap, f)); sum += ret; f -= ret; e.cap -= ret; edge[i^1].cap += ret; } } return sum; } void buildGraph(int lev){ tot = 0; memset(head, -1, sizeof(head)); for(int i = K + 1; i <= N; ++i) add(0, i, 1); for(int i = 1; i <= K; ++i) add(i, t, M); for(int i = K + 1; i <= N; ++i){ for(int j = 1; j <= K; ++j){ if(d[i][j] <= lev) add(i, j, 1); } } } bool dinic(){ int ret = 0; while(bfs()) ret += dfs(0, INF); return (ret >= C); } int main(){ while(~scanf("%d%d%d", &K, &C, &M)){ N = K + C; t = N + 1; for(int i = 1; i <= N; ++i) for(int j = 1; j <= N; ++j){ scanf("%d", &d[i][j]); if(d[i][j] == 0) d[i][j] = INF; } floyd(); int l = 0, r = 1e4, ans, mid; while(l < r){ mid = (l + r) >> 1; buildGraph(mid); if(dinic()) { ans = mid; r = mid; }else l = mid + 1; } printf("%d\n", ans); } return 0; }