pku 2112 Optimal Milking floyd + 二分 + 网络流

http://poj.org/problem?id=2112

题意:

给出K个挤奶的机器,C个奶牛,以及每个挤奶机器每天最多服务M头奶牛,给出他们的之间的距离。求奶牛到挤奶器处产奶,其满足小于等于M的情况下,最远距离的最小值。

思路:
不得不说这是一个很好的题目,首先我们看到的是机器每天工作量的限制,让我们联想到流的限制。我们首先二分枚举一个距离,然后建图源点s到挤奶器建边权值为M,奶牛到汇点e建边权值为1.然后枚举奶牛与挤奶器之间的距离,如果小于mid就建立一条权值为1的边,然后求最大流如果小于C继续增加,否则减小。 这里建图之前先用floyd求出任意两点之间的最短距离,这样保证枚举的任意两点距离最短。

//#pragma comment(linker,"/STACK:327680000,327680000")

#include <iostream>

#include <cstdio>

#include <cmath>

#include <vector>

#include <cstring>

#include <algorithm>

#include <string>

#include <set>

#include <functional>

#include <numeric>

#include <sstream>

#include <stack>

#include <map>

#include <queue>



#define CL(arr, val)    memset(arr, val, sizeof(arr))



#define inf 0x7f7f7f7f

#define lc l,m,rt<<1

#define rc m + 1,r,rt<<1|1

#define pi acos(-1.0)

#define ll long long

#define L(x)    (x) << 1

#define R(x)    (x) << 1 | 1

#define MID(l, r)   (l + r) >> 1

#define Min(x, y)   (x) < (y) ? (x) : (y)

#define Max(x, y)   (x) < (y) ? (y) : (x)

#define E(x)        (1 << (x))

#define iabs(x)     (x) < 0 ? -(x) : (x)int

#define OUT(x)  printf("%I64d\n", x)

#define lowbit(x)   (x)&(-x)

#define Read()  freopen("din.txt", "r", stdin)

#define Write() freopen("dout.txt", "w", stdout);



#define N 350



using namespace std;



struct node

{

    int v,w;

    int next;

}g[N*N];

int head[N],ct;



int mat[N][N];

int level[N];

int q[N*1000];



int K,C,M,n;



void add(int u,int v,int w)

{

    g[ct].v = v;

    g[ct].w = w;

    g[ct].next = head[u];

    head[u] = ct++;



    g[ct].v = u;

    g[ct].w = 0;

    g[ct].next = head[v];

    head[v] = ct++;

}



bool layer(int s,int e)

{

    int i;

    CL(level,-1);

    queue<int>q;

    q.push(s);

    level[s] = 1;

    while (!q.empty())

    {

        int u = q.front(); q.pop();

        for (i = head[u]; i != -1; i = g[i].next)

        {

            int v = g[i].v;

            int w = g[i].w;

            if (w > 0 && level[v] == -1)

            {

                level[v] = level[u] + 1;

                if (v == e)  return true;

                q.push(v);

            }

        }

    }

    return false;

}

int find(int s,int e)

{

    int i;

    int top = 1,u;

    int ans = 0;

    while (top)

    {

        if (top == 1) u = s;

        else u = g[q[top - 1]].v;

        if (u == e)

        {

            int MIN = inf,pos = 0;

            for (i = 1; i <= top - 1; ++i)

            {

                if (MIN > g[q[i]].w)

                {

                    MIN = g[q[i]].w;

                    pos = i;

                }

            }

            for (i = 1; i <= top - 1; ++i)

            {

                g[q[i]].w -= MIN;

                g[q[i]^1].w += MIN;

            }

            ans += MIN;

            top = pos;

        }

        else

        {

            for (i = head[u]; i != -1; i = g[i].next)

            {

                int w = g[i].w;

                int v = g[i].v;

                if (level[v] == level[u] + 1 && w > 0)

                {

                    q[top++] = i;

                    break;

                }

            }

            if (i == -1)

            {

                top--;

                level[u] = -1;

            }

        }

    }

    return ans;

}

int dinic(int s,int e)

{

    int ans = 0;

    while (layer(s,e))  ans += find(s,e);

    return ans;

}

void build(int s,int e,int mid)

{

    int i,j;

    CL(head,-1); ct = 0;

    for (i = 1; i <= K; ++i) add(s,i,M);

    for (i = K + 1; i <= n; ++i) add(i,e,1);

    for (i = 1; i <= K; ++i)

    {

        for (j = K + 1; j <= n; ++j)

        {

            if (mat[i][j] <= mid) add(i,j,1);

        }

    }

}

void floyd()

{

    int i,j,k;

    for (k = 1; k <= n; ++k)

    {

        for (i = 1; i <= n; ++i)

        {

            for (j = 1; j <= n; ++j)

            {

                if (mat[i][k] != inf && mat[k][j] != inf && mat[i][j] > mat[i][k] + mat[k][j])

                {

                    mat[i][j] = mat[i][k] + mat[k][j];

                }

            }

        }

    }

}

int main()

{

    //Read();



    int i,j;

    while (~scanf("%d%d%d",&K,&C,&M))

    {

        n = K + C;

        for (i = 1; i <= n; ++i)

        {

            for (j = 1; j <= n; ++j)

            {

                scanf("%d",&mat[i][j]);

                if (mat[i][j] == 0) mat[i][j] = inf;

            }

        }

        floyd();



        int s = 0, e = n + 1;

        int l = 0;

        int r = 200*n;

        int res = 0;

        while (l <= r)

        {

            int mid = (l + r)/2;

            build(s,e,mid);

            int ans = dinic(s,e);

           // printf("%d %d %d %d\n",ans,l,r,mid);

            if (ans == C)

            {

                res = mid;

                r = mid - 1;

            }

            else l = mid + 1;

        }

        printf("%d\n",res);

    }

    return 0;

}

  

 

你可能感兴趣的:(floyd)