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

时间:2022-08-27 09:46:14

原文地址: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]美食节 费用流+动态加边的更多相关文章

  1. &lbrack;BZOJ2879&rsqb; &lbrack;Noi2012&rsqb; 美食节 &lpar;费用流 &amp&semi; 动态加边&rpar;

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

  2. BZOJ 2879&colon; &lbrack;Noi2012&rsqb;美食节&lpar; 费用流 &plus; 动态加边 &rpar;

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

  3. &lbrack;NOI2012&rsqb;&lbrack;bzoj2879&rsqb; 美食节 &lbrack;费用流&plus;动态加边&rsqb;

    题面 传送门 思路 先看看这道题 修车 仔细理解一下,这两道题是不是一样的? 这道题的不同之处 但是有一个区别:本题中每一种车有多个需求,但是这个好办,连边的时候容量涨成$p\lbrack i\rbr ...

  4. &lbrack;BZOJ2879&rsqb;&lbrack;NOI2012&rsqb;美食节&lpar;费用流&rpar;

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

  5. BZOJ 2879 &lbrack;Noi2012&rsqb;美食节 &vert; 费用流 动态开点

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

  6. &lbrack;NOI2012&rsqb;美食节——费用流(带权二分图匹配)&plus;动态加边

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

  7. BZOJ 2879 美食节(费用流-动态加边)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2879 题意:有n道菜,每道菜需要b[i]份,m个厨师,第j个厨师做第i道菜需要时间a[i ...

  8. &lbrack;NOI2012&rsqb;美食节&lpar;费用流&rpar;

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

  9. &lbrack;BZOJ1070&rsqb; &lbrack;SCOI2007&rsqb; 修车 &lpar;费用流 &amp&semi; 动态加边&rpar;

    Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使 ...

随机推荐

  1. nginx日志切割脚本

    #!/bin/bash ip=`ifconfig eth0 | grep "inet addr" | cut -f 2 -d ":" | cut -f 1 -d ...

  2. JS 瀑布流布局

    瀑布流布局 HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8"> &l ...

  3. Oracle中左右外连接详解

    数据表的连接有:  1.内连接(自然连接): 只有两个表相匹配的行才能在结果集中出现 2.外连接: 包括 (1)左外连接(左边的表不加限制) (2)右外连接(右边的表不加限制) (3)全外连接(左右两 ...

  4. db2 字符串转换 数字

    今天使用聚合函数的时候 发现 varchar类型的是不可用的,所以呢就开始想办法解决 用到了转换函数cast(s.score as bigint) 然后有一个问题就是如果数据为空的话就会发生转换错误. ...

  5. 单位内部DNS架设及域名解析服务

    越来越多的企业将企业内部局域网通过光缆.交换机等高速互连设备连接起来,形成较大规模的中型网络,网络上的主机和用户也随之日渐增多.作为 Internet的缩影,企业内部网上的各类服务器(如WWW服务器. ...

  6. windows phone 浏览器 (1)

    原文:windows phone 浏览器 (1) windows phone 浏览器主要用的控件是phone:WebBrowser,该控件就是windows phone中的IE,在grid控件嵌套的g ...

  7. crontab如何设置秒级别的定时【转载】

    * * * * * date > /home/gamester88/test/nihao.txt * * * * * (sleep 10 && date >> /ho ...

  8. Intellij IDEA的下载安装与破解

    一,下载与安装 1.官网下载:https://www.jetbrains.com/idea/ 2.选择Windows对应版本安装 二,破解 1.下载破解补丁:http://idea.lanyus.co ...

  9. 51nod 1057 N的阶乘 &lpar;大数运算&rpar;

    输入N求N的阶乘的准确值.   Input 输入N(1 <= N <= 10000) Output 输出N的阶乘 Input示例 5 Output示例 120 压位: 每个数组元素存多位数 ...

  10. Solr系列四:Solr(solrj 、索引API 、 结构化数据导入)

    一.SolrJ介绍 1. SolrJ是什么? Solr提供的用于JAVA应用中访问solr服务API的客户端jar.在我们的应用中引入solrj: <dependency> <gro ...