• [费用流][动态开边] Jzoj P4371 作业分配


    Description

    暑假里,总有某些同学由于贪玩而忘记做作业。这些人往往要等到暑假快结束时才想起堆积如山的作业,但在这最后几天的时间里把这些作业做完已经不太现实了,于是“志同道合”的他们想出了一个妙招。
    假设现在有n科作业,他们把第i科作业按作业量平均分成ai份,他们总共有m个人,第j个人只愿意做其中任意的bj份作业,而且我们知道ai的和等于bj的和,以及把第i科作业的其中一份给第j个人做的时间是ci,j。现在他们想分配下各自的任务,一起把作业做完,然后再%#^&%^&#*%*%&^
    现在的问题来了,他们希望所有人做作业的总时间的和最小,你能帮助他们解决问题吗?
     

    Input

    输入文件的第一行有两个n,m表示有多少科作业和多少个人,第二行有n个数依次表示ai,第三行有m个数依次表示bj,最后n行,每行m个数表示ci,j。

    Output

    输出文件包含一行为最少的时间总和。
     

    Sample Input

    2 2
    3 5
    5 3
    1 2
    2 1

    Sample Output

    10
    【样例解释】
    第1个人做完所有的第1科作业以及第2科作业的其中2份,第2个人把第2科另外3份做完。
     
     

    Data Constraint

    第一个点           n<=5  m<=5  ai,bi<=15  sum(ai)<=20
    第二个点           n<=10  m<=10  ai,bi<=20  sum(ai)<=100
    第三个点           n<=30  m<=30  ai,bi<=600  sum(ai)<=10000
    第四个点到第十个点 n<=200  m<=200  ai,bi<=10000  sum(ai)<=1000000

    题解

    • 一眼,有点费用流的感觉
    • 建图很简单,每科向S源点连一条费用为0流量为a[i]的边
    • 每人向每科连一条费用为c[i][j]流量为a[j]的边
    • 最后每人向汇点T连一条费用为0流量为b[i]的边
    • 然后跑一遍费用流,这样就有40分了
    • 这题时限是500ms!!!
    • 所以,一开始将所有边加入图里会超时
    • 那么考虑一下动态加边
    • 就可以100分了
    • 动态加边的做法:
    • 动态加边就是在之前加入的最短边满流后才加的边
    • 也就是说我们一开始只加入与第i科最短的边(也就是做第i科需要最短时间的人)(快排排个序)
    • 如果在跑的过程中满流了,那么对于当前来说,费用绝对是最优的
    • 因为,我们是从最短加到最长,知道搞定为止
    • 所以当前的费用绝对是最优的
    • 然后我们就依次往后加边就好了

    代码

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<queue>
     4 #include<cstring>
     5 #include<algorithm>
     6 using namespace std;
     7 const int N=10005;
     8 const int inf=100000000;
     9 int n,m,cnt=1,last[N],t,f[N],d[N],s,a[510],b[510],k[N],num[N],ans,dis[N],w[N],mx;
    10 struct node{int d,v;}c[510][510];
    11 struct edge{int to,next,c,w;}e[N*100];
    12 queue<int> Q;
    13 void insert(int u,int v,int x,int y)
    14 {
    15      e[++cnt].to=v; e[cnt].c=x; e[cnt].w=y; e[cnt].next=last[u]; last[u]=cnt; 
    16     e[++cnt].to=u; e[cnt].c=0; e[cnt].w=-y; e[cnt].next=last[v]; last[v]=cnt;
    17 }
    18 bool spfa()
    19 {
    20     for (int i=s;i<=t;i++)
    21     {
    22         dis[i]=inf;
    23         f[i]=d[i]=0;
    24     }
    25     Q.push(s);
    26     f[s]=1; dis[s]=0; w[s]=inf;
    27     while (!Q.empty())
    28     {
    29         int u=Q.front(); Q.pop();
    30         for (int i=last[u];i;i=e[i].next)
    31             if (e[i].c&&e[i].w+dis[u]<dis[e[i].to])
    32             {
    33                 dis[e[i].to]=e[i].w+dis[u];
    34                 w[e[i].to]=min(w[u],e[i].c);
    35                 d[e[i].to]=i;
    36                 if (!f[e[i].to])
    37                 {
    38                     f[e[i].to]=1;
    39                     Q.push(e[i].to);
    40                 }   
    41               }
    42         f[u]=0;     
    43     }
    44     if (dis[t]<inf) return 1; else return 0;
    45 }
    46 void mcf()
    47 {
    48     int x=t;
    49     while (x!=s)
    50     {
    51         int i=d[x];
    52         e[i].c-=w[t];
    53         e[i^1].c+=w[t];
    54         x=e[i^1].to;
    55     }
    56     mx+=w[t];
    57     ans+=dis[t]*w[t];
    58 }
    59 void work()
    60 {
    61     while (spfa())
    62     {
    63         mcf();
    64         for (int i=1;i<=n;i++)
    65             while (!e[k[c[i][num[i]].d]].c&&num[i]<m) num[i]++,insert(i,n+c[i][num[i]].d,a[i],c[i][num[i]].v);
    66     }
    67 }
    68 bool cmp(node x,node y) { return x.v<y.v; }
    69 int main()
    70 {
    71     scanf("%d%d",&n,&m);
    72     s=0; t=m+n+1;
    73     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    74     for (int i=1;i<=m;i++) scanf("%d",&b[i]);
    75     for (int i=1;i<=n;i++)
    76     {
    77         
    78         for (int j=1;j<=m;j++) scanf("%d",&c[i][j].v),c[i][j].d=j;
    79         sort(c[i]+1,c[i]+m+1,cmp);
    80         num[i]=1;
    81         insert(i,n+c[i][1].d,a[i],c[i][1].v);
    82     }
    83     for (int i=1;i<=n;i++) insert(s,i,a[i],0);
    84     for (int i=1;i<=m;i++) insert(n+i,t,b[i],0),k[i]=cnt-1;
    85     work();
    86     printf("%d",ans);
    87     return 0;
    88 }
  • 相关阅读:
    MSSQLSERVER服务无法启动的解决方案
    引用类型和原始类型的对比(java)
    MVC中关于Membership类跟数据库的问题
    ASP.NET协作应用集成到trsids身份验证服务器的开发流程
    oracle的一知半解
    辨明你所从事的软件的类型
    sql数据库之间数据的转录
    设为首页 收藏(IE可用)
    如何缩减Try{}Catch{}Finally{}代码----定义一个公用的Try{}Catch{}Finally{}
    如何判断字符串是否存在数字
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9308457.html
Copyright © 2020-2023  润新知