【caioj 1119】牛挤奶 --- 二分+网络流-最大流

【题目描述】

FJ把K个挤奶机搬进了住着C头奶牛的牧场。挤奶机的编号为1~K,奶牛的编号为K+1~~K+C。每头奶牛到每台挤奶机距离不同。每台挤奶机每天最多服务M头奶牛。求一种分配方案, 使得走得最远的奶牛走过的距离最小化。输出此距离.

【输入格式】
数据第1行是3个整数K,C,M(1≤K≤30)(1≤C≤200)(1≤M≤15)
接下来是一个(K+C)×(K+C)的距离矩阵。矩阵元素为正并不超200。距离为0表示两个点之间无边存在。

【输出格式】
输出一个整数,即走得最远的奶牛走过的距离的最小化值。

【样例输入】

2 3 2

0 3 2 1 1

3 0 3 2 0

2 3 0 1 0

1 2 1 0 2

1 0 0 2 0

【样例输出】

2

分析

floyd预处理出最短距离,然后二分答案,用跑图判断

网络流建图:源点–W(1)–>奶牛–W(1)–>挤奶机–W(1)–>汇点
二分图建图:奶牛—->挤奶机

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>

#define IL inline
#define INF 0x7f7f7f7f
#define open(s) freopen(s".in","r",stdin); freopen(s".out","w",stdout);
#define close fclose(stdin); fclose(stdout);

using namespace std;

inline int read()
{
    char c=getchar();
    int sum=0,k=1;
    for(;'0'>c || c>'9';c=getchar())
        if(c=='-') k=-1;
    for(;'0'<=c && c<='9';c=getchar()) sum=sum*10+c-'0';
    return sum*k;
}

int K, C, M;
int S, T;
int dis[250][250];

struct Edge
{
    int to, nxt;
    int cap, flow;
    IL Edge(int v = 0, int nxt_ = 0, int c = 0, int f = 0)
    {
        to = v; nxt = nxt_; cap = c; flow = f;
    }
}edge[13000];
int last[250];
int cnt;
IL void add(int u, int v, int c)
{
    edge[cnt] = Edge(v, last[u], c, 0); last[u] = cnt++;
    edge[cnt] = Edge(u, last[v], 0, 0); last[v] = cnt++;
}

int dep[250];
int cur[250];

IL int min_(int x, int y) { return  x < y ? x : y ; }

IL bool Bfs()
{
    queue<int>Q;
    memset(dep, 0, sizeof(dep));
    dep[S] = 1;
    Q.push(S);
    for(int t = 1, u; t;)
    {
        u = Q.front(); Q.pop(); --t;
        for(int i = last[u]; i != -1; i = edge[i].nxt)
        if(!dep[edge[i].to] && edge[i].cap > edge[i].flow)
        {
            dep[edge[i].to] = dep[u] + 1;
            Q.push(edge[i].to); ++t;
        }
    }
    return dep[T];
}

IL int Dfs(int u, int a)
{
    if(u == T || !a) return a;
    int flow = 0, f; 
    for(int &i = cur[u]; i != -1; i = edge[i].nxt)
    if(dep[edge[i].to] == dep[u] + 1 && (f = Dfs(edge[i].to, min_(a, edge[i].cap - edge[i].flow))) > 0)
    {
        edge[i].flow += f;
        edge[i^1].flow -= f;
        flow += f;
        if(!(a -= f)) break;
    }
    return flow;
}

IL int check(int mid)
{
    memset(last, -1, sizeof(last)); cnt = 0;
    for(int i = 1; i <= K; ++i)
    {
        add(i, T, M);
        for(int j = 1; j <= C; ++j)
        {
            if(dis[j + K][i] <= mid)
                add(j + K, i, 1);
            if(i == 1) add(S, K + j, 1);
        }
    }

    int flow = 0;
    for(; Bfs();)
    {
        for(int i = S; i <= T; ++i) cur[i] = last[i];
        flow += Dfs(S, INF);
    }
    return flow;
}

int main()
{
    open("1119");

    K = read(); C = read(); M = read();
    int n = K + C;
    S = 0; T = n + 1;

    int l = 0, r = 0;

    for(int i = 1; i <= n; ++i)
    for(int j = 1; j <= n; ++j)
    {
        dis[i][j] = read();
        if(!dis[i][j]) dis[i][j] = INF; else
        if(dis[i][j] > r) r = dis[i][j];
    }

    for(int k = 1; k <= n; ++k)
    for(int i = 1; i < n; ++i)
    if(k != i && dis[i][k] != INF)
    for(int j = i + 1; j <= n; ++j)
    if(k != j && i != j && dis[k][j] != INF)
    {
        dis[i][j] = dis[j][i] = min_(dis[i][k] + dis[k][j], dis[i][j]);
        if(dis[i][j] > r) r = dis[i][j];
    }

    int ans = -1;
    for(int mid; l <= r;)
    {
        mid = (l + r) >> 1;
        if(check(mid) == C)
        {
            ans = mid;
            r = mid - 1;
        }else
            l = mid + 1;
    }

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

    close;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/79404669
今日推荐