[洛谷P2577] [ZJOI2005]午餐
洛谷题目链接:[ZJOI2005]午餐
题目描述
上午的训练结束了,THU ACM小组集体去吃午餐,他们一行N人来到了著名的十食堂。这里有两个打饭的窗口,每个窗口同一时刻只能给一个人打饭。由于每个人的口味(以及胃口)不同,所以他们要吃的菜各有不同,打饭所要花费的时间是因人而异的。另外每个人吃饭的速度也不尽相同,所以吃饭花费的时间也是可能有所不同的。
THU ACM小组的吃饭计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭。每个人打完饭后立刻开始吃,所有人都吃完饭后立刻集合去六教地下室进行下午的训练。
现在给定了每个人的打饭时间和吃饭时间,要求安排一种最佳的分队和排队方案使得所有人都吃完饭的时间尽量早。
假设THU ACM小组在时刻0到达十食堂,而且食堂里面没有其他吃饭的同学(只有打饭的师傅)。每个人必须而且只能被分在一个队伍里。两个窗口是并行操作互不影响的,而且每个人打饭的时间是和窗口无关的,打完饭之后立刻就开始吃饭,中间没有延迟。
现在给定N个人各自的打饭时间和吃饭时间,要求输出最佳方案下所有人吃完饭的时刻。
输入输出格式
输入格式:
第一行一个整数N,代表总共有N个人。
以下N行,每行两个整数 Ai,Bi。依次代表第i个人的打饭时间和吃饭时间。
输出格式:
一个整数T,代表所有人吃完饭的最早时刻。
输入输出样例
输入样例#1:
5
2 2
7 7
1 3
6 4
8 5
输出样例#1:
17
说明
所有输入数据均为不超过200的正整数。
题意: 有\(n\)个人.,每个人有一个排队时间和吃饭时间,两个窗口,窗口每时每刻都可以有一个人在排队,且一个人排完队后另一个人可以马上接着他排队,要使每个人都打完饭吃完最短需要多久.
题解: 首先我们先想一下如果只有一个窗口该如何记录最短时间.如果只有一个窗口,那么最短时间就只与排队顺序有关了,那么应该让谁排在前面呢?我们这里假设\(i\)的等待时间为\(wait[i]\),吃饭时间为\(eat[i]\),假设要让\(i\)排在\(j\)前面,就要满足:\(wait[i]+wait[j]+eat[j] <= wait[j]+wait[i]+eat[i])\)
化一下式子,可以得到\(eat[i] >= eat[j]\),也就是说,按照吃东西的时间从大到小排序,这样可以得到的结果是最优的.
那么如果有两个窗口呢?这里我们可以用DP的方法来维护一下.我们用状态\(f[i][j][k]\)表示前\(i\)个人都吃完饭,且在第一个窗口等待时间为\(j\),第二个为\(k\)所需要的最少时间.那么可以写出状态转移方程:$$f[i][j][k]=min(f[i][j][k], max(f[i-1][j-wait[i]][k], j+eat[i]))$$和$$f[i][j][k]=min(f[i][j][k], max(f[i-1][j][k-wait[i]], k+eat[i]))$$.
然而这样做的话时空复杂度是\(O(n*V^2)\)的,其中\(V=n^2\),显然这样的复杂度是过不了的.
那么我们需要对这个状态进行一些优化.
我们会发现前\(i\)个人的等待时间之和是可以确定的,也就是说,我们并不需要记录两个窗口的等待时间,只需要记录一个窗口的等待时间就可以算出另一个窗口的等待时间,可以设状态\(f[i][j]\)表示前\(i\)个人都吃完饭,并且第一个窗口等待时间为\(j\).这样定义的状态可以保证是唯一的.转移也类似上面的转移方法:$$f[i][j] =min(f[i][j], max(f[i-1][j-wait[i]], j+eat[i]))$$和$$f[i][j] = min(f[i][j], max(f[i-1][j], sum[i]-j+eat[i]))$$其中\(sum[i]\)表示前\(i\)个人的等待总时间.
#include<bits/stdc++.h>
using namespace std;
const int N = 200+5;
typedef int _int;
#define int long long
int n, sum[N], ans = 2e9;
int f[N][N*N];
struct people{
int wait, eat;
}a[N];
bool cmpp(people a, people b){ return a.eat > b.eat; }
_int main(){
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i].wait >> a[i].eat;
sort(a+1, a+n+1, cmpp);
for(int i = 1; i <= n; i++) sum[i] = sum[i-1]+a[i].wait;
memset(f, 127/3, sizeof(f)), f[0][0] = 0;
for(int i = 1; i <= n; i++)
for(int j = 0; j <= sum[n]; j++){
if(j >= a[i].wait) f[i][j] = min(f[i][j], max(f[i-1][j-a[i].wait], j+a[i].eat));
f[i][j] = min(f[i][j], max(f[i-1][j], sum[i]-j+a[i].eat));
}
for(int i = 0; i <= sum[n]; i++) ans = min(ans, f[n][i]);
cout << ans << endl;
return 0;
}
[洛谷P2577] [ZJOI2005]午餐的更多相关文章
- 【题解】洛谷P2577 [ZJOI2005] 午餐(DP+贪心)
次元传送门:洛谷P2577 思路 首先贪心是必须的 我们能感性地理解出吃饭慢的必须先吃饭(结合一下生活) 因此我们可以先按吃饭时间从大到小排序 然后就能自然地想到用f[i][j][k]表示前i个人在第 ...
- 洛谷P2577 [ZJOI2005]午餐 打饭时间作为容量DP
P2577 [ZJOI2005]午餐 )逼着自己做DP 题意: 有n个人打饭,每个人都有打饭时间和吃饭时间.有两个打饭窗口,问如何安排可以使得总用时最少. 思路: 1)可以发现吃饭时间最长的要先打饭. ...
- 洛谷P2577 [ZJOI2005]午餐 dp
正解:序列dp 解题报告: 传送门! 这题首先要想到一个显然的贪心:每个窗口的排队顺序都是按照吃饭时间从大到小排序的 证明如下: 这种贪心通常都是用微扰法,这题也不例外 现在假如已经确定了每个窗口有哪 ...
- 洛谷 P2577 [ZJOI2005]午餐
这道题目比较难想. 题解: 算法:贪心+dp 容易想到贪心:吃饭慢的先打饭节约时间, 所以先将人按吃饭时间从大到小排序. 然后就是dp了: 首先,应该想到f[i][j][k]:前i个人,在1号窗口打饭 ...
- 洛谷 P2577 [ZJOI2005]午餐 题解
每日一题 day56 打卡 Analysis 算法:贪心+dp 容易想到贪心:吃饭慢的先打饭节约时间, 所以先将人按吃饭时间从大到小排序. 然后就是dp了: 首先,应该想到f[i][j][k]:前i个 ...
- BZOJ1899或洛谷2577 [ZJOI2005]午餐
BZOJ原题链接 洛谷原题链接 解决这题得先想到一个贪心:吃饭慢的先排队. 并不会证明(感觉显然 设\(f[i][j][k]\)表示已经排好了前\(i\)人,第一个队伍需要花费的打饭时间为\(j\), ...
- 洛谷 2577 [ZJOI2005]午餐——序列dp
题目:https://www.luogu.org/problemnew/show/P2577 可以从只有一个窗口的角度思考出一个贪心结论.就是应当按吃饭时间(不算打饭时间)从大到小排序.这样交换相邻两 ...
- Luogu P2577 [ZJOI2005]午餐(dp)
P2577 [ZJOI2005]午餐 题面 题目描述 上午的训练结束了, \(THU \ ACM\) 小组集体去吃午餐,他们一行 \(N\) 人来到了著名的十食堂.这里有两个打饭的窗口,每个窗口同一时 ...
- 【洛谷P2577】[ZJOI2005]午餐
午餐 题目链接 DP题都辣么毒瘤的么.. 首先,看一下题解 我们就有了思路: 贪心:显然,让吃饭慢的先打饭,sort一遍(证明?不存在的.. DP:f[i][j][k]表示前i个人,窗口1的打饭时间为 ...
随机推荐
- ZOJ 3644 Kitty's Game(数论+DP)
Description Kitty is a little cat. She is crazy about a game recently. There arenscenes in the game( ...
- mysql数据库配置主从同步
MySQL主从同步的作用 .可以作为一种备份机制,相当于热备份 .可以用来做读写分离,均衡数据库负载 MySQL主从同步的步骤 一.准备操作 .主从数据库版本一致,建议版本5.5以上 .主从数据库数据 ...
- JavaScript初探系列之String的基本操作
1.字符串转换 字符串转换是最基础的要求和工作,你可以将任何类型的数据都转换为字符串,你可以用下面三种方法的任何一种: var myStr = num.toString(); // "19& ...
- 第一届"进化论杯"月赛 解题报告
Problem A: derivative 思路:水题.算出二阶导数,直接 printf 结果. 在求出二阶导数后可以不立刻化简,此时式中带有大量 e^(-x) 项.此时直接可以代入 ln|x0|,把 ...
- 《学习OpenCV》课后习题解答3
题目:(P104) 创建一个大小为100*100的三通道RGB图像.将它的元素全部置0.使用指针算法以(20,5)与(40,20)为项点绘制一个绿色平面. 解答: #include "cv. ...
- 201621044079WEEK作业08-集合
作业08-集合 1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 2. 书面作业 1. ArrayList代码分析 1.1 解释ArrayList的contains源代码 如 ...
- Node js MySQL简单操作
//win7环境下node要先安装MySQL的相关组件(非安装MySQL数据库),在cmd命令行进入node项目目录后执行以下语句 //npm install mysql var mysql = re ...
- 【Docker 命令】- start/stop/restart命令
docker start:启动一个或多少已经被停止的容器 docker stop:停止一个运行中的容器 docker restart :重启容器 语法: docker start [OPTIONS] ...
- ubuntu 只有客人会话登录(第一次深刻感受文件权限的威力 )
为了测试docker的挂载权限,把宿主机的/etc/passwd文件挂载到了虚机当中,进入虚机想看下能不能直接对我宿主机上的文件进行操作,把/etc/passwd删掉了最后十行...结果宿主机上的/e ...
- C#中的反射和扩展方法的运用
前段时间做了一个练手的小项目,采用的是三层架构,也就是Models,IDAL,DAL,BLL 和 Web , 在DAL层中各个类中有一个方法比较常用,那就是 RowToClass ,顾名思义,也就是将 ...