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;
}

  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值