POJ2112 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;
} 
原文地址:https://www.cnblogs.com/Lyush/p/3052077.html