zoukankan      html  css  js  c++  java
  • bzoj2879 [Noi2012] 美食节 (费用流)

    2879: [Noi2012]美食节

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 2231  Solved: 1177
    [Submit][Status][Discuss]

    Description

    CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节。作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴。他很快就尝遍了美食节所有的美食。然而,尝鲜的欲望是难以满足的。尽管所有的菜品都很可口,厨师做菜的速度也很快,小M仍然觉得自己桌上没有已经摆在别人餐桌上的美食是一件无法忍受的事情。于是小M开始研究起了做菜顺序的问题,即安排一个做菜的顺序使得同学们的等待时间最短。小M发现,美食节共有n种不同的菜品。每次点餐,每个同学可以选择其中的一个菜品。总共有m个厨师来制作这些菜品。当所有的同学点餐结束后,菜品的制作任务就会分配给每个厨师。然后每个厨师就会同时开始做菜。厨师们会按照要求的顺序进行制作,并且每次只能制作一人份。此外,小M还发现了另一件有意思的事情: 虽然这m个厨师都会制作全部的n种菜品,但对于同一菜品,不同厨师的制作时间未必相同。他将菜品用1, 2, ..., n依次编号,厨师用1, 2, ..., m依次编号,将第j个厨师制作第i种菜品的时间记为 ti,j 。小M认为:每个同学的等待时间为所有厨师开始做菜起,到自己那份菜品完成为止的时间总长度。换句话说,如果一个同学点的菜是某个厨师做的第k道菜,则他的等待时间就是这个厨师制作前k道菜的时间之和。而总等待时间为所有同学的等待时间之和。现在,小M找到了所有同学的点菜信息: 有 pi 个同学点了第i种菜品(i=1, 2, ..., n)。他想知道的是最小的总等待时间是多少。

    Input

      输入文件的第1行包含两个正整数n和m,表示菜品的种数和厨师的数量。 第2行包含n个正整数,其中第i个数为pi,表示点第i种菜品的人数。 接下来有n行,每行包含m个非负整数,这n行中的第i行的第j个数为ti,j,表示第j个厨师制作第i种菜品所需的时间。 输入文件中每行相邻的两个数之间均由一个空格隔开,行末均没有多余空格。

    Output

     输出仅一行包含一个整数,为总等待时间的最小值。

     

    同bzoj1070修车;

    每个厨师拆成$sum$(菜品总数)个点,每种菜品向厨师点连边,第$i$种菜品与第$j$名厨师的第$k$个点间的边流量为$1$,费用为$k*cost[i][j]$;

    源点连每种菜品,流量$1$、费用$0$,厨师点连汇点,流量$1$,费用$0$,跑最小费用最大流;

    然后GG

    看了题以为跟修车一样就十分naive地尝试写了一下,发现有300w条边,扑街;

    注意到向某厨师的第$k+1$个点连边的费用一定大于第$k$个点,因此可以考虑动态加边,在某厨师的第$k$个点被选择之后再连第$k+1$个点的边;

    AC GET☆DAZE

     

    ↓代码

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<string>
      5 #include<cmath>
      6 #include<algorithm>
      7 #include<vector>
      8 #include<queue>
      9 #define N 100039
     10 #define M 2000039
     11 #define inf 0x7fffffff
     12 #define ll long long
     13 using namespace std;
     14 struct edge
     15 {
     16     int from,to,next,cap,co;
     17 }net[2*M];
     18 int n,m,ans=0,S,T;
     19 int head[2*M],dis[N],pre[N],tot=-1,maxflow,mincost;
     20 int num[139],sum,cost[139][139];
     21 bool inq[N]={0};
     22 void add(int i,int j,int k,int c)
     23 {
     24     net[++tot]=(edge){i,j,head[i],k,c},head[i]=tot;
     25     net[++tot]=(edge){j,i,head[j],0,-c},head[j]=tot;
     26 }
     27 bool spfa()
     28 {
     29     queue<int> que;
     30     int a,b,sn,sl;
     31     for(a=S;a<=T;a++)
     32     {
     33         dis[a]=inf;
     34     }
     35     que.push(S);
     36     dis[S]=0,inq[S]=1;
     37     while(!que.empty())
     38     {
     39         a=que.front(),que.pop();
     40         for(b=head[a];b!=-1;b=net[b].next)
     41         {
     42             sn=net[b].to,sl=net[b].co;
     43             if(net[b].cap && dis[a]+sl<dis[sn])
     44             {
     45                 dis[sn]=dis[a]+sl;
     46                 pre[sn]=b;
     47                 if(!inq[sn])
     48                 {
     49                     inq[sn]=1;
     50                     que.push(sn);
     51                 }
     52             }
     53         }
     54         inq[a]=0;
     55     }
     56     return dis[T]^inf;
     57 }
     58 int mcf()
     59 {
     60     int flow=inf,a,i,j,k;
     61     for(a=pre[T];a!=-1;a=pre[net[a].from])
     62     {
     63         flow=min(flow,net[a].cap);
     64     }
     65     for(a=pre[T];a!=-1;a=pre[net[a].from])
     66     {
     67         mincost+=flow*net[a].co;
     68         net[a].cap-=flow,net[a^1].cap+=flow;
     69     }
     70     i=net[pre[T]].from,j=(i-n)/m+2,k=i+m; 
     71     a=i=(i-n)%m;
     72     if(!a)
     73     {
     74         i=m,j--;
     75     }
     76     if(k<T)
     77     {
     78         add(k,T,1,0);
     79         for(a=1;a<=n;a++)
     80         {
     81             add(a,k,1,j*cost[a][i]);
     82         }
     83     }
     84     return flow;
     85 }
     86 void Sinogi()
     87 {
     88     maxflow=0,mincost=0;
     89     while(spfa())
     90     {
     91         maxflow+=mcf();
     92     }
     93 }
     94 int main()
     95 {
     96     memset(pre,-1,sizeof(pre));
     97     memset(head,-1,sizeof(head));
     98     int a,b,c,d;
     99     scanf("%d%d",&n,&m);
    100     S=0;
    101     for(a=1;a<=n;a++)
    102     {
    103         scanf("%d",&b);
    104         sum+=b;
    105         add(S,a,b,0);
    106     }
    107     T=n+sum*m+1;
    108     for(a=1;a<=n;a++)
    109     {
    110         for(b=1;b<=m;b++)
    111         {
    112             scanf("%d",&cost[a][b]);
    113             add(a,n+b,1,cost[a][b]);
    114         }
    115     }
    116     for(a=1;a<=m;a++)
    117     {
    118         add(n+a,T,1,0);
    119     }
    120     Sinogi();
    121     printf("%d",mincost);
    122     return 0;
    123 }
    bzoj2879
    散りぬべき 時知りてこそ 世の中の 花も花なれ 人も人なれ
  • 相关阅读:
    fiddler---Fiddler模拟接口数据(mock)
    Intellij IDEA gradle项目目录介绍
    Windows netstat 查看端口、进程占用
    SpringMVC和spring常见面试题总结
    mybatis一级缓存二级缓存
    Mybatis常见面试题总结
    Spring容器
    深入理解JVM类加载机制
    理解Spring框架中Bean的5个作用域
    编程语言的分类与关系
  • 原文地址:https://www.cnblogs.com/Sinogi/p/7475414.html
Copyright © 2011-2022 走看看