POJ 2112:Optimal Milking

来源:互联网 发布:淘宝机器人自动回复 编辑:程序博客网 时间:2024/06/15 19:40

题目链接:http://poj.org/problem?id=2112

题目翻译:有K个挤奶机,每个挤奶机可以容纳M头牛,总共有C头牛要挤奶,问C头牛中怎样分配可以使

走最远距离的那头牛走的距离尽量小,求出这个最远距离的最小值。


输入:K,M,C。  然后K+C的方阵表示各个物体间距离。


解题思路:网络流+二分。

先Flody求每个奶牛到每个挤奶机的最短距离。

每个奶牛只能去一个挤奶机器。

建立超级源点S,超级汇点D,由超级源点到每一头奶牛建立一条边,其容量就是1,代表1头牛,

由每台机器向超级汇点引一条边,其容量就是M,然后采用二分的方法求解答案,我们假设maxdist

是个挺大的数吧,然后如果dist[i][j]  也就是第i头牛到第j个挤奶机器的最短路小于maxdist,则我们

可以建一条边由第i头牛到第j头牛,其容量为1,然后我们求这个图的最大流,如果我们发现当前最

大流是C,则说明所有的牛都已经有相应的挤奶机器挤奶,我们可以缩小这个maxdist看看答案范围

能够缩小,如果最大流小于C则,我们就要扩大maxdist,来找符合题目的距离。


#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#include <queue>using namespace std;const int INF = 0x3f3f3f3f;int Map[240][240],head[240],level[240],vis[240],cap[240][240];int K,C,M,S,D,maxdist,edgeNumber,minFlow,minFlowNode,maxFlow;  ///K台挤奶机,C头奶牛,每个机器可以容纳M头奶牛void Flody() {    for(int k = 1; k <= K+C; k++)        for(int i = 1; i <= K+C; i++)            for(int j = 1; j <= K+C; j++) {                if(Map[i][k] + Map[k][j] < Map[i][j])                    Map[i][j] = Map[i][k] + Map[k][j];            }}bool bfs() {    queue<int>qu;    memset(level,-1,sizeof(level));    level[S] = 0;    qu.push(S);    while(!qu.empty()) {        int u = qu.front();        qu.pop();        for(int i = 0; i <= K+C+1; i++) {            if(level[i]==-1 && cap[u][i] > 0) {                level[i] = level[u] + 1;                if(i == D)                    return true;                qu.push(i);            }        }    }    return false;}void dfs() {    int u,v,cur,i;    deque<int>qu;    memset(vis,0,sizeof(vis));    vis[S] = 1;    qu.push_back(S);    while(!qu.empty()) {        cur = qu.back();        if(cur == D){            minFlow = INF+1;            minFlowNode = S;            for(i = 1; i < qu.size(); i++) {                u = qu[i-1];                v = qu[i];                if(cap[u][v]>0 && minFlow>cap[u][v]) {                    minFlow = cap[u][v];                    minFlowNode = u;                }            }            maxFlow += minFlow;            for(i = 1; i < qu.size(); i++) {                u = qu[i-1];                v = qu[i];                cap[u][v] -= minFlow;                cap[v][u] += minFlow;            }            while(!qu.empty() && qu.back() != minFlowNode) {                vis[qu.back()] = 0;                qu.pop_back();            }        }else {            for(i = 1; i <= K+C+1; i++) {                if(cap[cur][i]>0 && level[i] == level[cur]+1 && vis[i]==0) {                    vis[i] = 1;                    qu.push_back(i);                    break;                }            }            if(i > K+C+1)                qu.pop_back();        }    }}///求最大流void dinic() {    maxFlow = 0;    while(bfs()) {        dfs();    }}///建图void buildGraph(int top){    memset(cap,0,sizeof(cap));    for(int i = K+1; i <= K+C; i++)        cap[S][i] = 1;    for(int i = 1; i <= K; i++)        cap[i][D] = M;    for(int i = K+1; i <= K+C; i++)        for(int j = 1; j <= K; j++) {            if(Map[i][j]<=top)                cap[i][j] = 1;        }}void solve() {    int ans = 1,low = 1,high = maxdist;    while(low <= high)    {        int mid = (low+high)/2;        buildGraph(mid);        dinic();        if(maxFlow == C) {            ans = mid;            high = mid - 1;        }else {            low = mid + 1;        }    }    printf("%d\n",ans);}int main(){    while(~scanf("%d%d%d",&K,&C,&M))    {        maxdist = 0;        for(int i = 1; i <= K+C; i++)            for(int j = 1; j <= K+C; j++){                scanf("%d",&Map[i][j]);                maxdist += Map[i][j];                if(Map[i][j] == 0 && i != j)  ///二者之间没有道路                    Map[i][j] = INF;            }        Flody();        S = 0;        D = K+C+1;        solve();    }    return 0;}