[洛谷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的打饭时间为 ...
随机推荐
- 微信小程序:封装全局的promise异步调用方法
微信小程序:封装全局的promise异步调用方法 一:封装 function POST(url, params) { let promise = new Promise(function (resol ...
- c# word 删除指定内容
1.首先简单的是获取得到的range,直接rangge.delete() 2.文本框的删除: foreach (Microsoft.Office.Interop.Word.Shape shape in ...
- BluetoothClass详解
一. BluetoothClass简介 1. 继承关系 public final class BluetoothClass extends Object implements Parcelable 该 ...
- object-oriented 第二次作业(2)
面向对象程序设计自学计划 由于我的英文实在是很差,所以我就没有去考虑看英文的课程视频.网络上的课程有很多,什么学校的也有,一开始我不知道该如何开始选择课程.感觉每个都还可以.后来在群里的看到别人推荐的 ...
- SpringMVC拦截器实现登录认证(转发)
感谢原作者,转发自:http://blog.csdn.net/u014427391/article/details/51419521 以Demo的形式讲诉拦截器的使用 项目结构如图: 需要的jar:有 ...
- Linux 路由 学习笔记 之一 相关的数据结构
http://blog.csdn.net/lickylin/article/details/38326719 从现在开始学习路由相关的代码,在分析代码之前, 我们还是先分析数据结构,把数据结构之间的关 ...
- JS DOM(2017.12.28)
一.获得元素节点的方法 document.getElementById() 根据Id获取元素节点 document.getElementsByName() 根据name获取元素节点 遍 ...
- node中的__dirname
先说结论:__dirname指的是当前文件所在文件夹的绝对路径. 测试路径如下: 即 根目录/dir0.js 根目录/path1/dir1.js 根目录/paht1/path2/dir2.js 每个d ...
- 关于设置Visaul Studio 2010 代码编辑界面背景的方法
1.打开代码编辑界面: 2.找到工具--选项: 3.打开选项后选中纯文本--项背景色: 4.点击自定义,找到自己需要的颜色: [注]: “项前景色”即代码的颜色: “项背景色”即背景颜色. 设置好后, ...
- MySQL错误解决10038
[错误解决]本地计算机上的mysql服务启动停止后,某些服务在未由其他服务或程序使用时将自动停止 标签: mysql计算机 2016-12-01 17:49 5508人阅读 评论(2) 收藏 举报 ...