poj 2112 二分枚举+最大流

传送门

题意:有k个挤奶机,c个奶牛,每个挤奶机可以挤m只,给i你一张邻接矩阵,问走最远的奶牛最少要走多远到挤奶机。

思路:呵呵了,一开始想成费用流了,结果一直wa,后来才发现费用流只能保证总费用最小,而不能使其中增广路费用的最大值最小,傻逼了。

在wa的无法自拔的时候,看了一眼芳哥博客,说是二分和最大流,瞬间明白了,这里就是二分枚举答案,看在这个最远值之内能否达到最大流,然后求出最小的能达到最大流的答案。

反思:没能仔细读题,对于i!=j的0距离,代表不能直接到达。。。。。没看仔细。。。。。哎~~~~。后来才加了floyed过了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 1<<29
using namespace std;
int fst[250],next[20000],node[20000],l[20000],cc[20000];
int c,k,m,en,ans,d[250],pre[250],f[20000],lu[250];
int a[300][300],flow;
bool vi[250];
void add(int u,int v,int con,int fee)
{
    next[en]=fst[u];
    fst[u]=en;
    node[en]=v;
    cc[en]=con;
    l[en]=fee;
    en++;
}
bool bfs(int s,int t,int ml)
{
    memset(vi,0,sizeof(vi));
    queue<int>q;
    q.push(s);
    vi[s]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=fst[u];i!=-1;i=next[i])
        {
            int v=node[i];
            if(cc[i]>f[i]&&l[i]<=ml&&!vi[v])
            {
                pre[v]=u;
                lu[v]=i;
                vi[v]=1;
                if(v==t)return true;
                q.push(v);
            }
        }
    }
    return false;
}
void ek(int s,int t,int ml)
{
    memset(f,0,sizeof(f));
    while(bfs(s,t,ml))
    {
        for(int i=t;i!=s;i=pre[i])
        {
            int v=lu[i];
            f[v]+=1;
            f[v^1]-=1;
        }
        flow+=1;
    }
}
void solve()
{
    int left=0,right=20000,mid;
    while(left<=right)
    {
        mid=(left+right)/2;
        flow=0;
        ek(0,k+c+1,mid);
        if(flow==c)
        {
            ans=mid;
            right=mid-1;
        }
        else left=mid+1;
    }
}
int main()
{
    while(scanf("%d%d%d",&k,&c,&m)!=EOF)
    {
        en=0;
        memset(fst,-1,sizeof(fst));
        int sum=k+c;
        for(int i=1; i<=sum; i++)
        {
            for(int j=1; j<=sum; j++)
            {
                scanf("%d",&a[i][j]);
                if(i!=j&&a[i][j]==0)a[i][j]=maxn;
            }
        }
        for(int x=1;x<=sum;x++)
        {
            for(int y=1;y<=sum;y++)
            {
                for(int z=1;z<=sum;z++)
                {
                    if(a[y][z]>a[y][x]+a[x][z])a[y][z]=a[y][x]+a[x][z];
                }
            }
        }
        for(int i=1; i<=k; i++)
        {
            for(int j=1; j<=c; j++)
            {
                add(i,k+j,1,a[i][k+j]);
                add(k+j,i,0,a[k+j][i]);
            }
            add(0,i,m,0);
            add(i,0,0,0);
        }
        for(int i=1; i<=c; i++)
        {
            add(k+i,sum+1,1,0);
            add(sum+1,k+i,0,0);
        }
        solve();
        cout<<ans<<endl;
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值