POJ-2112: Optimal Milking

keyword

最大流 二分探索 C++

問題概要

K(<30)個の搾乳機とC(<200)匹の牛がいる。搾乳機はM(<15)匹まで同時に処理できる。各搾乳機および各牛間の距離行列が与えられる。牛が移動する距離の最大値の最小化をする問題。

解法

最大値の最小化なので定石通り二分探索する。距離の上限を決めてやると2部グラフが構成できるので、あとは2部マッチングのようにsourceから牛へ容量1の辺を張り、搾乳機からsinkへ容量Mの辺を張ってやればよい。実装時間26分。

#include <cstdio>
#include <string.h>
#include <queue>
using namespace std;

const int MAX_V = 250;
const int INF = 1<<28;
int K, C, V, M;
int graph[MAX_V][MAX_V];

bool check(int limit){
    for(int i=0; i<V+2; i++)G[i].clear();
    for(int i=0; i<K; i++){
        add_edge(i,V+1,M);
    }
    for(int i=K; i<V; i++){
        add_edge(V,i,1);
    }
    for(int i=0; i<K; i++){
        for(int j=K; j<V; j++)if(graph[i][j]<=limit){
            add_edge(j,i,1);
        }
    }
    return max_flow(V,V+1)==C;
}

int solve(){
    for(int k=0; k<V; k++)for(int i=0; i<V; i++)for(int j=0; j<V; j++){
        graph[i][j] = min(graph[i][j], graph[i][k] + graph[k][j]);
    }
    int low=0, high=1<<20;
    while(high - low > 1){
        int mid = (high+low)/2;
        if(check(mid)) high = mid;
        else low = mid;
    }
    return high;
}

int main(){
    scanf("%d%d%d",&K,&C,&M);
    V = K + C;
    for(int i=0; i<K+C; i++){
        for(int j=0; j<K+C; j++){
            int x;
            scanf("%d",&x);
            graph[i][j] = x?x:INF;
        }
    }
    printf("%d\n",solve());
    return 0;
}