题目描述

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入格式

第一行有 2个整数 T(1≤T≤1000),和M(1≤M≤1000)。用一个空格隔开,T代表总共能够用来采药的时间,M 代表山洞里的草药的数目。

接下来的 M 行每行包括两个在 1 到 100 之间(包括 1 和 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出在规定的时间内可以采到的草药的最大总价值。

输入样例

70 3
71 100
69 1
1 2

输出样例

3

解法

动态规划

  1. 动态规划是递归的一种,一般通过双重循环逐步推出结果
  2. 要通过动态规划推出结果,必须保证每一步的结果不会影响到前面已经算好的结果

背包问题

本题是0/1背包问题,给出一个容量为T的采药总时间和M件价值为v[i],耗时为w[i]的草药(每棵草药只能采一次)

f[i]是一个数组,用来存储容量为i的背包能获得的价值最多是多少,故f[t]为最终所得

从物品出发

只有当背包剩余的容量大于一件物品时,才能装得下这件物品,获得这件物品的价值,因此我们可以从每件物品出发开始遍历

//从每件物品出发
for(int i=0;i<n;i++){

}

从j=t开始降序枚举

  1. 比方说现在要看第i件物品放不放,f[]已经计算了i-1次,记录了各自容量能装的最高的价值总量。
  2. 这时候f[j-w[i]]还是没装过第i件物品的价值量,用f[j-w[i]]+v[i]与f[j]进行比较,相当于装i和不装i的价值量比较,正合题意
  3. 如果j是从0开始升序枚举,怎么判断装不装i?按原来意思,f[j]去和f[j-w[i]]+v[i]比较?你会发现f[j-w[i]]可早就不是没装过第i件物品的价值量了,如果j-w[i]大于i的重量,它早就装上了i,哪还轮得到j来判断装不装,完全不合题意
//枚举可以装得下第i件物品的剩余容量,即遍历能装得下i物体的容量为j的背包
for(int i=0;i<n;i++){
	for(int j=t;j>=w[i];j--){
	
	}
}

本题解法

#include<iostream>
#include<cmath>

using namespace std;

int main(){
	int t=0,m=0;
	int f[1001]={},v[101]={},w[101]={};
	cin>>t>>m;
	for(int i=1;i<=m;i++){
		cin>>w[i]>>v[i];
	}
	for(int i=1;i<=m;i++){
		for(int j=t;j>=w[i];j--){
			f[j]=max(f[j-w[i]]+v[i],f[j]);
		}
	}
	cout<<f[t];
}