poj 2112 二分枚举+最大流

来源:互联网 发布:新买的被子要洗吗 知乎 编辑:程序博客网 时间:2024/04/29 13:23

传送门

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

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

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

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

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#define maxn 1<<29using 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;}