P1687 机器人小Q - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
成功派送完这个大单后,餐厅决定引入一名新成员:机器人小 Q。小 Q 的到来让餐厅的客源增加了不少,但是,一段时间之后,新的问题又出现了,小 Q 和我们可不一样,如果要让他工作的话,我们得给他输入能量以保持体力,而小 Q 的能量菜单表上已经按一定顺序给出了 N 个单位的能量值,但是每个单位的能量由于来源不同,需要消耗一定的时间摄入。已知小 Q 每天充电的时间上限值为 119,如果时间超出的话就会自动崩溃,大家都想让小 Q 留下来,经过研究之后,决定派 HWX 和 XYF 去和老板谈判,考虑角度不一样,LXC 老板才不想听什么辛酸流泪史,他只想知道,若是想让小 Q 获得 k 单位的能量(也就是能量表中可以不接受某些能量)最少需要几天来充电。
第一行,两个整数,N,K 分别表示小 Q 的能量菜单上有 N 个单位的能量,想获取其中的 k 个。
第二行,N个整数,分别是第 i 个单位能量需要的充电时间。
仅一行,一个整数,为最少需要天数。
如果永远不能达到题目要求,输出 You can't do it.
输入 #1复制
7 3 1 119 119 1 120 120 118
输出 #1复制
2
只接收 1,1,1181。显然这需要 2 天。
对于 30% 的数据,有 1≤K≤N≤20。
对于 100% 的数据,有 1≤K≤N≤3000。
多关键字dp
我们很容易想到将状态划分为 f[i][j] :表示从前 i 个能量中选取 j 个的最小天数;
但我们发现:每天充电上限为 119 这一状态无法体现,即这个划分方式并非不重不漏的,而且这一状态对天数的影响至关重要;
因此我们可以将这个划分方式稍微修改一下,划分为 f[i][j][1] 和 f[i][j][0];
f[i][j][1] 表示表示从前 i 个能量中选取 j 个的最小天数,f[i][j][0] 表示这种情况下的当天消耗的时间;
(即,以天数为第一关键字,以最后一天充电的时长为第二关键字选取最优解)
这样,我们就将整个问题划分成了多个不重不漏的子集;
则状态的转移过程为:
f[i−1][j−1][0]+w[i]>119
这时候我们应该增加新的一天来使用第i 个能量单位
因此比较f[i−1][j−1][1]+1 与f[i][j][1] 的大小关系。
若f[i−1][j−1][1]+1
若f[i][j][1]=f[i−1][j−1][1]+1,f[i][j][0]=w[i]
f[i−1][j−1][1]+1=f[i][j][1],那么这时候比较第二关键字
f[i][j][0]=min(w[i],f[i][j][0])
f[i−1][j−1][0]+w[i]≤119
这时候考虑将第
i 个能量单位追加到最后一天内,仍然按序比较两个关键字
若 f[i−1][j−1][1]
f[i][j][1]=f[i−1][j−1][1],f[i][j][0]=f[i−1][j−1][0]+w[i]
若f[i−1][j−1][1]=f[i][j][1]
此时比较第二关键字
f[i][j][0]=min(f[i][j][0],f[i−1][j−1][0]+w[i])
如果我们不选取第 i 个能量单位
这时候直接继承前面的状态f[i][j][0]=f[i−1][j][0],f[i][j][1]=f[i−1][j][1]
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include