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
", ans);
    }
    return 0;
}