链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2879
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)。他想知道的是最小的总等待时间是多少。
思路:动态建点,每次如果能有增广路,就新建点。
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#define N 200005
int tot,go[],first[],next[],flow[],cost[];
int op[],from[N],edge[N],dis[N],vis[N],c[*N];
int a[][],n,m,p[N],ans,S,T,all;
int read(){
int t=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (''<=ch&&ch<=''){t=t*+ch-'';ch=getchar();}
return t*f;
}
void insert(int x,int y,int z,int l){
tot++;go[tot]=y;next[tot]=first[x];first[x]=tot;flow[tot]=z;cost[tot]=l;
}
void add(int x,int y,int z,int l){
insert(x,y,z,l);op[tot]=tot+;insert(y,x,,-l);op[tot]=tot-;
}
bool spfa(){
for (int i=;i<=T;i++) dis[i]=0x3f3f3f3f,vis[i]=;
int h=,t=;dis[S]=;c[]=S;
while (h<=t){
int now=c[h++];
for (int i=first[now];i;i=next[i]){
int pur=go[i];
if (flow[i]&&dis[pur]>dis[now]+cost[i]){
dis[pur]=dis[now]+cost[i];
from[pur]=now;
edge[pur]=i;
if (vis[pur]) continue;
vis[pur]=;
c[++t]=pur;
}
}
vis[now]=;
}
return dis[T]!=0x3f3f3f3f;
}
void updata(){
int mn=0x7fffffff,x,y;
for (int i=T;i!=S;i=from[i]){
mn=std::min(mn,flow[edge[i]]);
if (from[i]==S){
x=(i-)/all+;
y=(i)%all+;
}
}
for (int i=T;i!=S;i=from[i]){
ans+=mn*cost[edge[i]];
flow[edge[i]]-=mn;
flow[op[edge[i]]]+=mn;
}
for (int i=;i<=m;i++)
add((x-)*all+y,n*all+i,,y*a[i][x]);
}
int main(){
m=read();n=read();
S=;
for (int i=;i<=m;i++){
p[i]=read();
all+=p[i];
}
T=m+n*all+;
for (int i=;i<=n*all;i++)
add(S,i,,);
for (int i=;i<=m;i++)
add(i+n*all,T,p[i],);
for (int i=;i<=m;i++)
for (int j=;j<=n;j++)
a[i][j]=read();
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
add((i-)*all+,n*all+j,,a[j][i]);
while (spfa()) updata();
printf("%d\n",ans);
}