poj2112 二分+floyd+最大流 好题

  这个题的意思是有K个挤奶机器, 和C个牛,一个机器每天最多服务W个奶牛,  如果将牛和机器看成顶点那么告诉两顶点之间的距离, 那么请最小化奶牛去挤奶的时候走的路的最大值, 首先我们可以使用floyd求出奶牛去某个挤奶机器的最短路径,然后二分一个答案, 建图, 我们再定义一个超级源点和超级汇点, 源点指向机器, 权值为W, 机器和奶牛之间也有边, 满足条件为边的长度小于等于二分的答案, 权值为1, 每个奶牛到汇点也有一个边权值为1, 求出此图的最大流观察其是否等于奶牛的数量, 代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;
int K, C, M;
int d[250][250];

const int maxn = 500;
const int inf = 0x3f3f3f3f;

struct Dinic
{
    int n;       //n个顶点
    struct edge
    {
        int from, to, cap;
    };
    vector<int> G[maxn];
    vector<edge> e;
    int level[maxn], iter[maxn];

    void init()
    {
        for(int i=0; i<=n; i++) G[i].clear();
        e.clear();
    }

    void add_edge(int u, int v, int cap)
    {
        e.push_back((edge)
        {
            u, v, cap
        });
        e.push_back((edge)
        {
            v, u, 0
        });
        int m = e.size();
        G[u].push_back(m-2);
        G[v].push_back(m-1);
    }

    void bfs(int s)
    {
        memset(level, -1, sizeof(level));
        queue<int> que;
        level[s] = 0;
        que.push(s);
        while(!que.empty())
        {
            int u = que.front();
            que.pop();
            for(int i=0; i<G[u].size(); i++)
            {
                edge &te = e[G[u][i]];
                if(te.cap>0 && level[te.to]<0)
                {
                    level[te.to] = level[u] + 1;
                    que.push(te.to);
                }
            }
        }
    }

    int dfs(int v, int t, int f)
    {
        if(v == t) return f;
        for(int &i=iter[v]; i<G[v].size(); i++)
        {
            edge &tpe = e[G[v][i]];
            if(tpe.cap>0 && level[v]<level[tpe.to])
            {
                int d = dfs(tpe.to, t, min(f, tpe.cap));
                if(d > 0)
                {
                    tpe.cap -= d;
                    e[G[v][i]^1].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }

    int max_flow(int s, int t)
    {
        int flow = 0;
        for(;;)
        {
            bfs(s);
            if(level[t]<0) return flow;
            memset(iter, 0, sizeof(iter));
            int f;
            while((f=dfs(s, t, 0x3fffffff)) > 0)
                flow += f;
        }
    }
} di;

void floyd()
{
    int n = K+C;
    for(int k=1; k<=n; k++)
    for(int i=1; i<=n; i++)
    for(int j=1; j<=n; j++)
        d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
}

bool check(int mid)
{
    di.n = K+C+2;   //0超级源点 machine 1-K cow K+1-K+C  K+C+1超级汇点
    di.init();
    for(int i=1; i<=K; i++)       //机器
    {
        for(int j=1+K; j<=C+K; j++)   if(d[i][j]<=mid) //奶牛
        {
            int u=i, v=j;
            di.add_edge(u, v, 1);
        }
        di.add_edge(0, i, M);
    }
    for(int j=1; j<=C; j++) di.add_edge(K+j, K+C+1, 1);
    int f = di.max_flow(0, K+C+1);
    return f==C;
}

int main()
{
    while(scanf("%d%d%d", &K, &C, &M)==3)
    {
        for(int i=1; i<=K+C; i++)
            for(int j=1; j<=K+C; j++)
            {
                scanf("%d", &d[i][j]);
                if(i!=j && d[i][j]==0) d[i][j] = inf;
            }
        floyd();
        int l=0, r=100000;
        int ans;

        while(l <= r)
        {
            int mid = (l+r)/2;
            if(check(mid))
            {
                ans = mid;
                r = mid - 1;
            }
            else l = mid + 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/xingxing1024/p/5244973.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值