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

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

Sample Input

3 2
3 1 1
5 7
3 6
8 9

Sample Output

47

【样例说明】
厨师1先制作1份菜品2,再制作2份菜品1。点这3道菜的3个同学的等待时间分别为3,3+5=8,3+5+5=13。
厨师2先制作1份菜品1,再制作1份菜品3。点这2道菜的2个同学的等待时间分别为7,7+9=16。
总等待时间为3+8+13+7+16=47。
虽然菜品1和菜品3由厨师1制作更快,如果这些菜品都由厨师1制作,总等待时间反而更长。如果按上述的做法,将1份菜品1和1份菜品3调整到厨师2制作,这样厨师2不会闲着,总等待时间更短。
可以证明,没有更优的点餐方案。

【数据规模及约定】
对于100%的数据,n <= 40, m <= 100, p <= 800, ti,j <= 1000(其中p = ∑pi,即点菜同学的总人数)。
每组数据的n、m和p值如下:
测试点编号 n m p
1 n = 5 m = 5 p = 10
2 n = 40 m = 1 p = 400
3 n = 40 m = 2 p = 300
4 n = 40 m = 40 p = 40
5 n = 5 m = 40 p = 100
6 n = 10 m = 50 p = 200
7 n = 20 m = 60 p = 400
8 n = 40 m = 80 p = 600
9 n = 40 m = 100 p = 800
10 n = 40 m = 100 p = 800

这题和修车那个题一毛一样……
只不过这个数据范围恶心的一比……
普通做法肯定不行
所以我用了(从题解里抄的)动态加边
每次找增广路径的时候,若当前是某个厨师的倒数第k道菜,且该厨师的边只连到倒数第k道
那么就把该厨师倒数第k+1道连上边即可

 #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define MAXN (100000+10)
#define MAXM (5000000+10)
using namespace std;
queue<int>q;
bool visit[MAXN];
int pre[MAXN];
int n,m,k,s,e=,Ans,Fee;
int num_edge;
int head[MAXN];
int dis[MAXN];
bool used[MAXN];
int INF;
int t[][],p[],sump;
int cnt[MAXN];
struct node
{
int to;
int next;
int Flow;//残留网络
int Cost;
} edge[MAXM*]; void add(int u,int v,int l,int c)
{
edge[++num_edge].to=v;
edge[num_edge].next=head[u];
edge[num_edge].Flow=l;
edge[num_edge].Cost=c;
head[u]=num_edge;
} bool Spfa(int s,int e)
{
// memset(pre,-1,sizeof(pre));
memset(dis,0x7f,sizeof(dis));
q.push(s);
dis[s]=;
used[s]=true;
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=head[x]; i!=; i=edge[i].next)
if (dis[x]+edge[i].Cost<dis[edge[i].to] && edge[i].Flow>)
{
dis[edge[i].to]=edge[i].Cost+dis[x];
pre[edge[i].to]=i;
if (!used[edge[i].to])
{
used[edge[i].to]=true;
q.push(edge[i].to);
}
}
used[x]=false;
}
return (dis[e]!=INF);
} void MCMF(int s,int e)
{
while (Spfa(s,e))
{
int d=INF,x;
for (int i=e; i!=s; i=edge[((pre[i]-)^)+].to)
d=min(d,edge[pre[i]].Flow);
for (int i=e; i!=s; i=edge[((pre[i]-)^)+].to)
{
edge[pre[i]].Flow-=d;
edge[((pre[i]-)^)+].Flow+=d;
if (edge[((pre[i]-)^)+].to==s) x=i;//这一次增广的是厨师那坨点的哪个点
}
Fee+=d*dis[e]; int a=(x-)/sump+,b=(x-)%sump+;
if (b<cnt[a]) return;
cnt[a]++;
for (int i=; i<=n; ++i)
{
add((a-)*sump+b+,m*sump+i,,cnt[a]*t[i][a]);
add(m*sump+i,(a-)*sump+b+,,-cnt[a]*t[i][a]);
}
}
} int main()
{
memset(&INF,0x7f,sizeof(INF));
scanf("%d%d",&n,&m);
for (int i=; i<=m; ++i) cnt[i]=;
for (int i=; i<=n; ++i)
scanf("%d",&p[i]),sump+=p[i];
for (int i=; i<=n; ++i)
for (int j=; j<=m; ++j)
scanf("%d",&t[i][j]);
for (int i=; i<=m*sump; ++i)
{
add(s,i,,);
add(i,s,,);
}
for (int i=; i<=n; ++i)
{
add(m*sump+i,e,p[i],);
add(e,m*sump+i,,);
}
for (int i=; i<=m; ++i) //第i个厨师
for (int k=; k<=n; ++k)
{
add((i-)*sump+,m*sump+k,,t[k][i]);
add(m*sump+k,(i-)*sump+,,-t[k][i]);
}
MCMF(s,e);
printf("%d\n",Fee);
}

2879. [NOI2012]美食节【费用流】的更多相关文章

  1. BZOJ 2879: [Noi2012]美食节( 费用流 + 动态加边 )

    倒着做菜..然后考虑为当前的人做菜对后面的人的影响就可以了..要动态加边 --------------------------------------------------------------- ...

  2. BZOJ.2879.[NOI2012]美食节(费用流SPFA)

    题目链接 /* 同"修车":对于每个厨师拆成p个点表示p个时间点,每个人向m个厨师每个时间点连边 这样边数O(nmp)+网络流 ≈O(nm*p^2)(假设SPFA线性) = GG ...

  3. BZOJ 2879 [Noi2012]美食节 | 费用流 动态开点

    这道题就是"修车"的数据加强版--但是数据范围扩大了好多,应对方法是"动态开点". 首先先把"所有厨师做的倒数第一道菜"和所有菜连边,然后跑 ...

  4. [NOI2012]美食节(费用流)

    题目描述 CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽管所有的菜品都 ...

  5. [NOI2012]美食节——费用流(带权二分图匹配)+动态加边

    题目描述 小M发现,美食节共有n种不同的菜品.每次点餐,每个同学可以选择其中的一个菜品.总共有m个厨师来制作这些菜品.当所有的同学点餐结束后,菜品的制作任务就会分配给每个厨师.然后每个厨师就会同时开始 ...

  6. 【bzoj2879】[Noi2012]美食节 费用流+动态加边

    原文地址:http://www.cnblogs.com/GXZlegend 题目描述 CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他 ...

  7. 【BZOJ 2879】[Noi2012]美食节 费用流

    思路同修车,就是多了一个骚气的操作:动态加边,我们通过spfa流的过程可以知道,我们一次只会跑一流量,最后一层边跑过就不会再悔改,所以说我们只会用到一大片里面的很少的点,所以我们如果可以动态加边的话我 ...

  8. [BZOJ2879][NOI2012]美食节(费用流)

    设sm为所有p之和,套路地对每道菜建一个点,将每个厨师拆成sm个点,做的倒数第i道菜的代价为time*i. S向每道菜连边<0,p[i]>(前者为代价后者为流量),i菜到j厨师的第k个点连 ...

  9. [BZOJ2879] [Noi2012] 美食节 (费用流 & 动态加边)

    Description CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽 ...

  10. BZOJ 2879: [Noi2012]美食节

    2879: [Noi2012]美食节 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1834  Solved: 969[Submit][Status] ...

随机推荐

  1. DDD Quickly - 读书笔记

    读后感:关于领域驱动设计,过去多多少少用到一些.所以,这本精简版看起来很快,很多概念很熟悉,它帮助我把散乱的知识串起来.最后,Eric Evans谈到一点,本来软件的发展是向着处理复杂的业务逻辑走的, ...

  2. 【学习笔记】--- 老男孩学Python,day14 python内置函数大全

    参考:  https://www.cnblogs.com/pyyu/p/6702896.html http://www.runoob.com/python3/python3-built-in-func ...

  3. Implementation:Sunday 字符串匹配

    int sunday(string str, string pattern) { int str_len = str.length(); int pat_len = pattern.length(); ...

  4. Myeclipse打war包方法

    Myeclipse三种打包方法第一种方法打开Myeclipse如图操作. 如果该项目已存在需要移除之后在进行第三步,接着往下走. 项目打war包成功,推荐使用第一种方法. 第二种方法https://b ...

  5. thinkphp3.2 success方法和redirect方法

    $this->redirect('showlist',array(),3,'添加成功'); $this->success('添加成功',U('showlist'),3);

  6. TOMCAT配置SSL认证为HTTPS协议服务

     1 . 问题概述 很多安全性要求较高的系统,都会使用安全套接字层(SSL)进行信息交换, Sun为了解决在Internet上的实现安全信息传输的解决方案.它实现了SSL和TSL(传输层安全)协议 ...

  7. linux 搜索文件内容并输出命令 grep、-i、-v ^#

    grep /bin/grepgrep -iv [指定字条串] [文件]在文件中搜索字符串匹配的行并输出-i 不区分大小写 -v 排除指定字符串 grep -i java /etc/profile gr ...

  8. jedis spring集成

    jedis spring集成把jedis的核心对象交给spring管理.jedis核心对象:配置文件.连接池配置对象.连接池.集成方式有两种:spring-data-redis:自己封装 前提:要有一 ...

  9. 实现serializable接口的作用

    最重要的两个原因是: 1.将对象的状态保存在存储媒体中以便可以在以后重新创建出完全相同的副本: 2.按值将对象从一个应用程序域发送至另一个应用程序域. 实现serializable接口的作用是就是可以 ...

  10. vs2017 调试时出现 cannot connect to runtime process错误

    用Visual Studio 2017 .net core进行开发时 ,调试运行项目时出现如下错误 解决方案,调试>选项,取消勾选,关闭对JavaScript的调试