zoukankan      html  css  js  c++  java
  • poj3686The Windy's(费用流)

    Description
    The Windy’s is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receives N orders for toys. The manager knows that every order will take different amount of hours in different workshops. More precisely, the i-th order will take Zij hours if the toys are making in the j-th workshop. Moreover, each order’s work must be wholly completed in the same workshop. And a workshop can not switch to another order until it has finished the previous one. The switch does not cost any time.

    The manager wants to minimize the average of the finishing time of the N orders. Can you help him?

    Input
    The first line of input is the number of test case. The first line of each test case contains two integers, N and M (1 ≤ N,M ≤ 50).
    The next N lines each contain M integers, describing the matrix Zij (1 ≤ Zij ≤ 100,000) There is a blank line before each test case.

    Output
    For each test case output the answer on a single line. The result should be rounded to six decimal places.

    Sample Input
    3
    3 4
    100 100 100 1
    99 99 99 1
    98 98 98 1
    3 4
    1 100 100 100
    99 1 99 99
    98 98 1 98
    3 4
    1 100 100 100
    1 99 99 99
    98 1 98 98

    Sample Output
    2.000000
    1.000000
    1.333333

    分析:
    学姐这道题用的是KM算法,然而我的KM只会n^4的,
    所以果断选择费用流

    这道题的建图需要好好考虑,
    首先明确:每个订单所消耗的时间是车间完成订单的时间加上订单等待的时间
    我们设在车间A需要完成k个订单,
    消耗的总时间是t1+(t1+t2)+(t1+t2+t3)…+(t1+t2+…+tk)
    转换一下就是t1*k+t2*(k-1)+t3*(k-2)……
    我们就找到了规律:
    当第i个订单在第j个车间是倒数第k个任务时,
    总消耗时间需要加上订单i在车间对应消耗时间的k倍

    那这个建图就稍微明朗一点了
    把每个车间拆成n个,(这就变成了一个n*m的矩阵)
    分别表示每个任务作为这个车间的倒数第x个任务
    每个任务向n*m矩阵中的每一个点连边
    任务i向车间j的第k个点连边
    就表示,任务i分配到了车间j并且作为所有在车间j完成的任务中的倒数第k个
    所以费用就变成了:k*W[i][j]

    这里写图片描述

    tip

    一直RE,对拍的时候有RE还有WA,感觉自己的脸太黑了
    debug了半天,发现是自己的队列开少了(要开到1w+)

    之后经历的阶段就是WA了
    我又发现自己在输出的时候没有换行
    但是还是WA,拍也拍不出什么东西来,我弃疗了
    (我的对拍数据都是按照题目要求随机的)

    给个AC代码,和我的思路一样

    给我们的启示就是
    空间一定要好好算,特别是队列的空间(15*N应该差不多了,真要保险的话N*N)
    考试的时候一定要用文件操作检验一下自己的输入输出是否符合题意

    //这里写AC不了的代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    
    using namespace std;
    
    const int INF=0x33333333;
    const int N=3000;
    int n,m,pre[N],st[N],tot,W[55][55],dis[N];
    bool p[N];
    int s,t,q[N<<4],tou,wei;
    struct node{
        int x,y,nxt,v,c;
    };
    node way[N*N];
    
    void add(int u,int w,int z,int cc)
    {
        tot++;
        way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];way[tot].v=z;way[tot].c=cc;st[u]=tot;
        tot++;
        way[tot].x=w;way[tot].y=u;way[tot].nxt=st[w];way[tot].v=0;way[tot].c=-cc;st[w]=tot;
    }
    
    int spfa(int s,int t)
    {
        tou=wei=0;
        memset(p,1,sizeof(p));
        memset(pre,-1,sizeof(pre));
        for (int i=s;i<=t;i++) dis[i]=INF;
        dis[s]=0; p[s]=0;
        q[++wei]=s;
        do
        {
            int r=q[++tou];
            for (int i=st[r];i!=-1;i=way[i].nxt)
                if (way[i].v&&dis[way[i].y]>dis[r]+way[i].c)
                {
                    dis[way[i].y]=dis[r]+way[i].c;
                    pre[way[i].y]=i;
                    if (p[way[i].y])
                    {
                        p[way[i].y]=0;
                        q[++wei]=way[i].y;
                    }
                }
            p[r]=1;
        }
        while (tou<wei);
        return dis[t]!=INF;
    }
    
    int doit()
    {
        int ans=0;
        while (spfa(s,t))
        {
            int sum=INF;
            for (int i=t;i!=s;i=way[pre[i]].x) 
                sum=min(sum,way[pre[i]].v);
            ans=ans+sum*dis[t];
            for (int i=t;i!=s;i=way[pre[i]].x)
                way[pre[i]].v-=sum,
                way[pre[i]^1].v+=sum;
        }
        return ans;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            memset(st,-1,sizeof(st));
            tot=-1;
            scanf("%d%d",&n,&m);
            s=0;t=m*n+n+1;
            for (int i=1;i<=n;i++) 
                for (int j=1;j<=m;j++)
                    scanf("%d",&W[i][j]);
            for (int i=1;i<=n;i++) add(s,i,1,0);
            for (int i=1;i<=n;i++)
                for (int j=1;j<=n;j++)
                    for (int k=1;k<=m;k++)
                        add(i,n+(j-1)*m+k,1,W[i][k]*j);
            for (int i=n+1;i<=n*m+n;i++) add(i,t,1,0);
            printf("%0.6lf
    ",(double)doit()/n);
        }
        return 0;
    }
  • 相关阅读:
    vmware ubuntu 异常关机无法连接到网络
    Speed up GCC link
    常用的一些解压命令
    Log4j 漏洞复现
    Test Case Design method Boundary value analysis and Equivalence partitioning
    CCA (Citrix Certified Administrator) exam of “Implementing Citrix XenDesktop 4”
    What is Key Word driven Testing?
    SAP AGS面试小结
    腾讯2013终端实习生一面
    指针的引用
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673115.html
Copyright © 2011-2022 走看看