1775:采药
描述
- 辰辰是个很有潜能、天资聪颖的孩子,他的梦想是称为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
输入
- 输入的第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出
- 输出只包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
样例输入
-
70 3 71 100 69 1 1 2
样例输出
3
我从学DP 到现在已经过去两个月了,现在唯一就是知道DP是动态规划,剩下就咸鱼了。所以我决定复习DP,写写DP的题。
来说一说今天的主题:背包问题。
背包问题最开始是这样的:
现在你有一个容量有限制的背包,还有许多有体积和价值的物品,物品的体积和价值各不相同。而背包问题问的就是在限定的体积下,你最多能装多大价值的物品。
基本上裸的背包题都是这个套路,当然价值可以变成时间什么的,像“采药”这道题,背包就是有限的时间,而价值就是采一种药的时间(多写写背包问题就能明显发现一道题是不是背包)。
好了,开始上课。
首先,给出背包问题的模板
#include <bits/stdc++.h> using namespace std; const int maxn = 102, maxT = 1005; int f[maxn][maxT]; //i个物品选择一些物品, 总体积为j int main() { int T, n; cin >> T >> n; for (int i = 1; i <= n; ++i) { int V, C; cin >> V >> C; for (int j = 0; j <= T; ++j) f[i][j] = f[i - 1][j]; //不选这个物品 for (int j = 0; j + V <= T; ++j) //选这个物品 if ((f[i][j + V]) < (f[i - 1][j] + C)) (f[i][j + V]) = (f[i - 1][j] + C); } cout << f[n][T] << endl; }
能看懂的就可以跳过下面的部分然后去A题了,没看懂的不要着急,我会慢慢讲。
先解释一下各变量和数组都是干什么的。
f[i][j]表示背包容量为j时选了i件物品的最大价值,T,n分别表示背包容量,物品件数,V C就是每件物品的体积和价值。
每输入一组数据,就将状态更新一次,代码的注释也写得很清楚,我们的策略是默认先不选择这个物品,所以f[i][j] = f[i - 1][j]是将当前状态记为和之前一样的状态,就相当于没有选择这个物品;而在更新的时候我们判断只要装入它不超容量,并且价值比原价值大的话,就装入它。
P.S.这是一道极其典型的背包问题,是最基础的背包问题,因为状态只有“0”和“1”(不装和装)两种,所以被称作“01背包”。