
题目来源
https://www.acwing.com/problem/content/12/
题目
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出 字典序最小的方案。这里的字典序是指:所选物品的编号所构成的序列。物品的编号范围是1…N。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一行,包含若干个用空格隔开的整数,表示最优解中所选物品的编号序列,且该编号序列的字典序最小。
物品编号范围是 1…N。
数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
1 | 4 5 |
输出样例
1 | 1 4 |
本题DP思想
1.
dp数组的定义:dp[i][j]表示考虑了是否选第i个物品以及之后的所有物品之后背包容量不超过j的最优解(价值最大)
2.
状态转移:dp[i][j] = max(dp[i+1][j],dp[i+1][j-v[i]]),状态可以通过(选,不选)来进行转移,它是由上一状态不选第i个物品或者上一状态选第i个物品转移得到.
- 当dp[i][j] = dp[i+1][j]上一状态且不选第i个物品:这时候的上一状态根据定义就是,考虑第i+1个物品以及之后的所有物品,且背包容量最大不超过j时这个状态,由于未选所以当前状态是直接由上一状态转移
- 当dp[i][j] = dp[i+1][j-v[i]]+w[i]上一状态选第i个物品:这时候的上一状态根据定义就是,考虑第i+1个物品以及之后的所有物品,且背包容量最大不超过j-v[i]时这个状态(状态转移之后背包体积为j,那么转移之前背包体积肯定就是减去选这个物品的体积啦),所以当前状态等于上一状态加上当前所选物品的价值
- 由于求的最优解,所以要从这两种状态转移中选择价值最大的
3.
初始化:由于dp是从最后一个物品开始,所以初始状态是dp[n+1][j],套上状态定义就是考虑了第n+1个物品及其以后的所以物品且,背包最大体积不超过j的最优解。由于不存在第n+1个物品及其以后的所有物品,所以这时候dp[n+1]x的最优解就是0
4.
本题输出状态转移路径的解释:我们已经有状态转移数组了,我们再通过状态转移数组倒推具体是怎样转移的;可以这样理解,我们记录各种状态转移,并且得到了最优解,现在我们背包里已经装了东西(最优价值),我们枚举每一件物品判断这件物品是否装入了背包里,如果装入了我们就将物品编号输出,然后将该物品从背包中取出,关键就在于怎么判断它是否装入了?这时候就要用到状态转移数组:m-当前最大背包容量,我们判断dp[i]m这个状态是否是dp[i+1]m-v[i]通过装入第i个物品所转移得到的如果是则输出选择的物品序号,并将该物品从背包中取出,取出后背包最大体积为m = m-v[i],下一次我们又判断dp[i+1][m]这个状态是否是dp[i+1+1][m-v[i+1]]转移得到,代码处还有样例解释
5.
为什么要倒着dp?
题目要求要输出字典序最小,如果1,2,3与1,2,4都能得到最优解,那么应该输出1,2,3.能选3就不能跳过3不选。所以我们应该倒着dp(用下面这个定义考虑,dp[1][V]就表明考虑了第一个及其以后的物品->也就是所有物品后,背包体积不超过V的时刻)然后顺着考虑转移路径,这个定义就是在表明,现在我们背包里已经装了东西(最优价值),我们枚举每一件物品判断这件物品是否装入了背包里,如果装入了我们就将物品编号输出,然后将该物品从背包中取出,怎么表达取出物品?就是背包的最大体积减少!
v1.5.2