zoukankan      html  css  js  c++  java
  • POJ 2112 Optimal Milking

    这题我读懂题意后,蒙了,没思路,有思路也是不可行的。。。

    果断看解题报告……都是二分+floy+最大流;写的很简单,看不懂;于是看代码!一看更蒙了!

    怎么用二分的方法,试着去找ans呢?感觉挺无语的!

    二分+最短路+最大流:先用floy求出各个奶牛到各个挤奶器的最短距离(或者说求出各个挤奶器到各个奶牛的最短距离)显然,这个是必须的,因为题中给的距离不一定是最短的!然后再用二分的方法去找答案,即在0~max(max为奶牛到挤奶器可能的最大距离,我认为是200*200=40000)用二分查找的方法去找最大距离的最小值;不断用mid的值去建网络流图添加源点0,汇点n+1,源点到所有挤奶器的距离为m即newmap[0][1..k]=m;奶牛到汇点的距离为1即newmap[k+1...n][n+1]=1;当map[挤奶器][奶牛]的距离<=mid时,建立边newmap[挤奶器][奶牛]=1;其它的边都初始化为0;然后求出maxflow,判断maxflow是否等于c;若等于令high=mid;若不等于令low=mid+1;最后low将会等于high就是最终的结果。概括地说一下:当用值mid去建网络图时,则保证了所有奶牛和挤奶器的距离的最大值为mid,就是试着看当它们的最大距离为mid时,是否满足所有的牛都可以挤奶(^_^),这个最大流嘛,很强大,没法子解释-----只可意会不可言传!

    View Code
    #include <stdio.h>
    #include <memory.h>

    #define N 232
    #define MAXVAL 40000

    int map1[N][N],map2[N][N];
    int k,c,m,n;

    int getData()
    {
    int i,j;

    if(EOF==scanf("%d %d %d",&k,&c,&m)) return 0;//改为EOF仍是WA,看来不是EOF的问题
    n=k+c;
    for(i=1;i<=n;i++)
    {
    for(j=1;j<=n;j++)
    {
    scanf("%d",map1[i]+j);
    if(i!=j && 0==map1[i][j]) map1[i][j]=MAXVAL;
    }
    }

    return 1;
    }

    void floyd()
    {
    int i,j,k;
    for(k=1;k<=n;k++)
    for(i=1;i<=n;i++)
    if(MAXVAL!=map1[i][k])
    for(j=1;j<=n;j++)
    if(map1[i][k]+map1[k][j]<map1[i][j])
    map1[i][j]=map1[i][k]+map1[k][j];
    }

    void buildGraph(int val)
    {
    int i,j;

    memset(map2,0,sizeof(map2));
    for(i=1;i<=k;i++) map2[0][i]=m;
    for(i=k+1;i<=n;i++) map2[i][n+1]=1;

    for(i=1;i<=k;i++)
    for(j=k+1;j<=n;j++)
    if(map1[i][j]<=val) //map2[i][j]=map2[j][i]=1;//终于发现这里map[j][i]=1错了!!
    map2[i][j]=1;
    }

    int queue[N],font,rear,pre[N];
    int Edmonds_Karp()
    {
    int v,u,minflow,maxflow=0;

    while(1)
    {
    memset(pre,-1,sizeof(pre)); pre[0]=0;
    font=rear=-1; queue[++rear]=0;

    while(font<rear)
    {
    v=queue[++font];
    for(u=1;u<=n+1;u++)
    {
    if(map2[v][u] && -1==pre[u])
    pre[u]=v,queue[++rear]=u;
    }
    if(-1!=pre[n+1]) break;
    }
    if(-1==pre[n+1]) break;

    minflow=MAXVAL;
    // for(u=pre[n+1];u;u=pre[u])//发现错误:调试① u=pre[n+1],那么汇点和前一个点没更新
    for(u=n+1;u;u=pre[u])
    if(minflow>map2[pre[u]][u]) minflow=map2[pre[u]][u];

    for(u=n+1;u;u=pre[u])
    map2[pre[u]][u]-=minflow,map2[u][pre[u]]+=minflow;

    maxflow+=minflow;
    }

    return maxflow;
    }

    void binarySearch()
    {
    int low=0,high=MAXVAL,mid;

    while(low<high)
    {
    mid=(low+high)>>1;
    buildGraph(mid);

    if(c==Edmonds_Karp())
    high=mid;
    else low=mid+1;
    }

    printf("%d\n",high);
    }

    void preprocessing()
    {
    floyd();
    }

    void solve()
    {
    while(getData())
    {
    preprocessing();
    binarySearch();
    }

    }

    int main()
    {
    //reopen("input.txt","r",stdin);

    solve();

    return 0;
    }

    588k 350ms

    传说中还有一种方法:

    二分+最短路+二分多重匹配

    其实这个方法上一个更容易理解呵,用mid的去建二分图,看看是否能够匹配成功!

    二分匹配是1:1,二分多重匹配是1:m(m:1);

    二分多重匹配也可以通过“拆点”的方法即1:m,可以把1拆成m点就成了1:1,就可以用二分匹配做了

    View Code
    #include <stdio.h>
    #include <memory.h>

    #define N 232
    #define MAXVAL 40000

    int map[N][N];//map2[N][N];
    int k,c,m,n;

    int getData()
    {
    int i,j;

    if(EOF==scanf("%d %d %d",&k,&c,&m)) return 0;//改为EOF仍是WA,看来不是EOF的问题
    n=k+c;
    for(i=1;i<=n;i++)
    {
    for(j=1;j<=n;j++)
    {
    scanf("%d",map[i]+j);
    if(i!=j && 0==map[i][j]) map[i][j]=MAXVAL;
    }
    }

    return 1;
    }

    void floyd()
    {
    int i,j,k;
    for(k=1;k<=n;k++)
    for(i=1;i<=n;i++)
    if(MAXVAL!=map[i][k])
    for(j=1;j<=n;j++)
    if(map[i][k]+map[k][j]<map[i][j])
    map[i][j]=map[i][k]+map[k][j];
    }

    //int nodevp[202];//发现错误:这里的nodevp数组大小202,可能会小!
    int nodevp[232];//应为232,因为奶牛的编号是从k+1开始到n,这样一改AC了!!
    int nodeu[6000],next[6000],ind;
    int machine[32][15],cnt[32];
    int flag[32];

    void addedge(int v,int u)
    {
    nodeu[ind]=u;
    next[ind]=nodevp[v];
    nodevp[v]=ind++;
    }

    void buildGraph(int val)
    {
    int i,j;

    memset(nodevp,-1,sizeof(nodevp)); ind=0;

    for(i=1;i<=k;i++)
    for(j=k+1;j<=n;j++)
    if(map[i][j]<=val)
    addedge(j,i);
    }

    int DFS(int v)
    {
    int i,j,u;
    for(i=nodevp[v];~i;i=next[i])
    {
    u=nodeu[i];
    if(flag[u]) continue;
    flag[u]=1;
    if(cnt[u]<m)
    {
    machine[u][cnt[u]++]=v;
    return 1;
    }
    for(j=0;j<m;j++)
    {
    if(DFS(machine[u][j]))
    {
    machine[u][j]=v;
    return 1;
    }
    }
    }

    return 0;
    }
    int match()
    {
    int v;

    memset(cnt,0,sizeof(cnt));

    for(v=k+1;v<=n;v++)
    {
    memset(flag,0,sizeof(flag));
    if(!DFS(v)) return 0;
    }

    return 1;
    }


    void binarySearch()
    {
    int low=0,high=MAXVAL,mid;

    while(low<high)
    {
    mid=(low+high)>>1;
    buildGraph(mid);

    if(match()) high=mid;
    else low=mid+1;
    }

    printf("%d\n",high);
    }

    void preprocessing()
    {
    floyd();
    }

    void solve()
    {
    while(getData())
    {
    preprocessing();
    binarySearch();
    }

    }

    int main()
    {
    // freopen("input.txt","r",stdin);

    solve();

    return 0;
    }

    424k 63ms (⊙o⊙)…这么快额!

  • 相关阅读:
    上海汉得面试:
    二叉树的遍历
    操作系统知识总结
    mysql单表查询&&多表查询(职员表14+9)
    数据库查询
    数据库设计三大范式及事务
    某硕笔试题mysql数据库部分(较为全面)
    java 读取excel 将数据插入到数据库
    java 读取excel 正常 xls
    java 读取excel(Map结构)xls
  • 原文地址:https://www.cnblogs.com/fornever/p/2406491.html
Copyright © 2011-2022 走看看