【bzoj2879】[Noi2012]美食节 费用流+动态加边
原文地址:http://www.cnblogs.com/GXZlegend
题目描述
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)。他想知道的是最小的总等待时间是多少。
输入
输入文件的第1行包含两个正整数n和m,表示菜品的种数和厨师的数量。 第2行包含n个正整数,其中第i个数为pi,表示点第i种菜品的人数。 接下来有n行,每行包含m个非负整数,这n行中的第i行的第j个数为ti,j,表示第j个厨师制作第i种菜品所需的时间。 输入文件中每行相邻的两个数之间均由一个空格隔开,行末均没有多余空格。
输出
输出仅一行包含一个整数,为总等待时间的最小值。
样例输入
3 2
3 1 1
5 7
3 6
8 9
样例输出
47
题解
动态加边+费用流
这道题和 修车 类似,然而数据范围大了若干倍,直接做会T。
于是可以动态加边,当且仅当第i名厨师的倒数第j道菜做完,才加点(i,j+1)和对应的边。
如此高端。。。
具体方法:
1.拆m名厨师为c*m个,其中c=∑pi,并编号为厨师(i,j),表示做应做的倒数第i道菜的第j名厨师。将编号转化为数字为(i-1)*m+j(转化方法和网上一些题解不同,其实没什么区别)。
2.连S->(i,j),容量为1,费用为0(其实也可以一样动态连边,不过优化作用不大);
连k+c*m->T,容量为p[k],费用为0.
3.连(1,j)->k+c*m,容量为1,费用为time[k][j]。
4.跑费用流,同时找到T->S路径上from值为S的点,设为厨师(x,y)。跑完费用流以后,加边(x+1,y)->k+c*m,容量为1,费用为time[k][j]*(x+1)。
最后的最小费用就是答案。
#include <cstdio>
#include <cstring>
#include <queue>
#define N 100010
#define M 3000010
using namespace std;
queue<int> q;
int n , m , c , p[50] , d[50][110] , head[N] , to[M] , val[M] , cost[M] , next[M] , cnt = 1 , s , t , dis[N] , inq[N] , from[N] , pre[N];
void add(int x , int y , int v , int c)
{
to[++cnt] = y , val[cnt] = v , cost[cnt] = c , next[cnt] = head[x] , head[x] = cnt;
to[++cnt] = x , val[cnt] = 0 , cost[cnt] = -c , next[cnt] = head[y] , head[y] = cnt;
}
bool spfa()
{
int x , i;
memset(dis , 0x3f , sizeof(dis));
memset(from , -1 , sizeof(from));
dis[s] = 0 , q.push(s);
while(!q.empty())
{
x = q.front() , q.pop() , inq[x] = 0;
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && dis[to[i]] > dis[x] + cost[i])
{
dis[to[i]] = dis[x] + cost[i] , from[to[i]] = x , pre[to[i]] = i;
if(!inq[to[i]]) inq[to[i]] = 1 , q.push(to[i]);
}
}
}
return ~from[t];
}
int mincost()
{
int ans = 0 , i , k , x , y;
while(spfa())
{
k = 0x3f3f3f3f;
for(i = t ; i != s ; i = from[i])
{
k = min(k , val[pre[i]]);
if(from[i] == s) x = (i - 1) / m + 1 , y = (i - 1) % m + 1;
}
ans += k * dis[t];
for(i = t ; i != s ; i = from[i]) val[pre[i]] -= k , val[pre[i] ^ 1] += k;
for(i = 1 ; i <= n ; i ++ ) add(m * x + y , c * m + i , 1 , d[i][y] * (x + 1));
}
return ans;
}
int main()
{
int i , j;
scanf("%d%d" , &n , &m);
s = 0;
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &p[i]) , c += p[i];
t = c * m + n + 1;
for(i = 1 ; i <= n ; i ++ )
for(j = 1 ; j <= m ; j ++ )
scanf("%d" , &d[i][j]);
for(i = 1 ; i <= c * m ; i ++ ) add(s , i , 1 , 0);
for(i = 1 ; i <= n ; i ++ ) add(c * m + i , t , p[i] , 0);
for(i = 1 ; i <= m ; i ++ )
for(j = 1 ; j <= n ; j ++ )
add(i , c * m + j , 1 , d[j][i]);
printf("%d\n" , mincost());
return 0;
}
【bzoj2879】[Noi2012]美食节 费用流+动态加边的更多相关文章
- [BZOJ2879] [Noi2012] 美食节 (费用流 & 动态加边)
Description CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽 ...
- BZOJ 2879: [Noi2012]美食节( 费用流 + 动态加边 )
倒着做菜..然后考虑为当前的人做菜对后面的人的影响就可以了..要动态加边 --------------------------------------------------------------- ...
- [NOI2012][bzoj2879] 美食节 [费用流+动态加边]
题面 传送门 思路 先看看这道题 修车 仔细理解一下,这两道题是不是一样的? 这道题的不同之处 但是有一个区别:本题中每一种车有多个需求,但是这个好办,连边的时候容量涨成$p\lbrack i\rbr ...
- [BZOJ2879][NOI2012]美食节(费用流)
设sm为所有p之和,套路地对每道菜建一个点,将每个厨师拆成sm个点,做的倒数第i道菜的代价为time*i. S向每道菜连边<0,p[i]>(前者为代价后者为流量),i菜到j厨师的第k个点连 ...
- BZOJ 2879 [Noi2012]美食节 | 费用流 动态开点
这道题就是"修车"的数据加强版--但是数据范围扩大了好多,应对方法是"动态开点". 首先先把"所有厨师做的倒数第一道菜"和所有菜连边,然后跑 ...
- [NOI2012]美食节——费用流(带权二分图匹配)+动态加边
题目描述 小M发现,美食节共有n种不同的菜品.每次点餐,每个同学可以选择其中的一个菜品.总共有m个厨师来制作这些菜品.当所有的同学点餐结束后,菜品的制作任务就会分配给每个厨师.然后每个厨师就会同时开始 ...
- BZOJ 2879 美食节(费用流-动态加边)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2879 题意:有n道菜,每道菜需要b[i]份,m个厨师,第j个厨师做第i道菜需要时间a[i ...
- [NOI2012]美食节(费用流)
题目描述 CZ市为了欢迎全国各地的同学,特地举办了一场盛大的美食节.作为一个喜欢尝鲜的美食客,小M自然不愿意错过这场盛宴.他很快就尝遍了美食节所有的美食.然而,尝鲜的欲望是难以满足的.尽管所有的菜品都 ...
- [BZOJ1070] [SCOI2007] 修车 (费用流 & 动态加边)
Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使 ...
随机推荐
- Python测量时间,用time.time还是time.clock
在计算机领域有多种时间.第一种称作CPU时间或执行时间,用于测量在执行一个程序时CPU所花费的时间.第二种称作挂钟时间,测量执行一个程序时的总时间.挂钟时间也被称作流逝时间或运行时间.与CPU时间相比 ...
- IDEA 安装配置及操作总结(新手必看)
Jetbrains官网下载IDEA15 我们在浏览器输入网址https://www.jetbrains.com/.选择相应的系统版本,下载最新版本的IDEA15,Windows系统双击安装文件,根据界 ...
- LeetCode705. Design HashSet
题目 不使用任何内建的哈希表库设计一个哈希集合 具体地说,你的设计应该包含以下的功能 add(value):向哈希集合中插入一个值. contains(value) :返回哈希集合中是否存在这个值. ...
- XStream 工具类 [ XmlUtil ]
pom.xml <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId> ...
- iPhone 横屏时默认会放大文字的问题
有人说用 html { text-size-adjust: 100%; }我发现这个并不能解决问题.下面代码可以完美解决. 添加标签:<meta name="viewport" ...
- HTML5--混合布局
1.先上效果图,大家来看看 2.代码如下: <!doctype html> <meta charset='utf-8' content='text/html' /> <h ...
- python__基础 : 类的__new__方法与实现一个单例
__new__ : 这个方法的作用主要是创建一个实例,在创建实例时首先会调用 __new__方法 ,然后调用__init__对实例进行初始化, 如果想修改 __new__ 这个方法,那么最后要 ret ...
- input标签中的name
<input>标签是java web的jsp页面中最常用的标签,特别是用来在页面和servlet中传递内容, 但是我们看到<input>标签中有很多内容,这边我们只提一下主要的 ...
- 4.1 基本类型和引用类型的值【JavaScript高级程序设计第三版】
ECMAScript 变量可能包含两种不同数据类型的值:基本类型值和引用类型值.基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象. 在将一个值赋给变量时,解析器必须确定这个值是基 ...
- HyperLedger Fabric 1.4 区块链技术定义(2.1)
区块链技术指使用点对点传输.共识机制.加密算法等技术,保证分布式数据库区块写入链中数据的一致性,达到去中心化和不可篡改的目的. 区块链就是一种特殊的分布式数据库,使用现有的各种成熟的技术, ...