【NOI2012】美食节

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) 。他想知道的是最小的总等待时间是多少。

Solution

这道题和盗版飞扬的小鸟是一样的,但是要打spfa才能过。

Code

#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=500007;
int i,j,k,l,n,m,ans;
int p[maxn],t[1007][1007],S,T,o,hou;
int first[maxn*2],next[maxn*2],last[maxn*2],chang[maxn*2],fan[maxn*2],cost[maxn*2],num,pp;
int bz[maxn],d[maxn],id,now[maxn],sh[maxn],data[maxn],ci;
void add(int x,int y,int z,int o){
    last[++num]=y;next[num]=first[x];first[x]=num;chang[num]=z;cost[num]=o;fan[num]=num+1;
    last[++num]=x;next[num]=first[y];first[y]=num;chang[num]=0;cost[num]=-o;fan[num]=num-1;
}
bool spfa(){
    int head,tail,now,i,j,p,q;
    fo(i,S,T)d[i]=0x7fffffff;q=d[0];
    bz[0]=1;d[0]=0;
    data[1]=0;
    head=0;tail=1;
    while(headwhile(i!=0){
            if(chang[i]&&d[last[i]]>d[now]+cost[i]){
                d[last[i]]=d[now]+cost[i];
                sh[last[i]]=i;
                if (!bz[last[i]]){
                    data[++tail]=last[i];
                    bz[last[i]]=1;
                }
            }
            i=next[i];
        }
        bz[now]=0;
    }
    if(d[T]!=q)return 1;return 0;
}
void zeng(){
    int i=sh[T],j=0x7fffffff,k=0;
    for(;i;i=sh[last[fan[i]]])
    j=min(j,chang[i]),k+=cost[i],chang[i]-=j,chang[fan[i]]+=j;;
    ans+=j*k;
   // for(i=sh[T];i;i=sh[last[fan[i]]])

    int hou=last[fan[sh[T]]]-n;
    if(hou%pp){
        hou++;
        int a=(hou-1)/pp+1,b=((hou-1)%pp+1);
        add(n+hou,T,1,0);
        fo(i,1,n){
            int v=t[i][a]*b;
            add(i,n+hou,1,v);
        }
    }
}
int main(){
//  freopen("fan.in","r",stdin);
    scanf("%d%d",&n,&m);
    fo(i,1,n){
        scanf("%d",&p[i]);
        pp+=p[i];
        add(S,i,p[i],0);
    }
    S=0,T=pp*m+n+1;
    fo(i,1,n){
        fo(j,1,m){
            scanf("%d",&t[i][j]);
        }
    }
    fo(i,1,n)fo(j,1,m)add(i,n+(j-1)*pp+1,1,t[i][j]);
    o=0;
    fo(j,1,m)add(n+(j-1)*pp+1,T,1,0);
    while(spfa())zeng(); 
    printf("%d\n",ans);
}

你可能感兴趣的:(noi,网络流,zkw,费用流)