- V(i,j)=V(i-1,j)时,说明没有选择第i 个商品,则回到V(i-1,j);
- V(i,j)=V(i-1,j-w(i))+v(i)时,说明装了第i个商品,该商品是最优解组成的一部分,随后我们得回到装该商品之前,即回到V(i-1,j-w(i));
- 一直遍历到i=0结束为止,所有解的组成都会找到。
4 8 2 3 3 4 4 5 5 6
注意此二维矩阵并不代表选取了谁,正真要求选了谁的时候要从最后一个推导
横行代表的是背包当前的容量——不一定是连续操作肯定是一行一行进行操作,但是所表示的价值就不一定了有可能如果图所示,选择了第二件商品和第三件商品。
选中了商品必定是执行的是max后面的部分,而不是继承上一个商品的价值
注意往回推的时候是逆序往回推4->3->2->1知道那间商品有被选中
- 最优解为V(4,8)=10,而V(4,8)!=V(3,8)却有V(4,8)=V(3,8-w(4))+v(4)=V(3,3)+6=4+6=10,所以第4件商品被选中,并且回到V(3,8-w(4))=V(3,3);
- 有V(3,3)=V(2,3)=4,所以第3件商品没被选择,回到V(2,3);
- 而V(2,3)!=V(1,3)却有V(2,3)=V(1,3-w(2))+v(2)=V(1,0)+4=0+4=4,所以第2件商品被选中,并且回到V(1,3-w(2))=V(1,0);
- 有V(1,0)=V(0,0)=0,所以第1件商品没被选择。
#include<iostream> using namespace std; int w[1010],v[1010]; int dp[1010][1010]; int main() { int n,volume; cin>>n>>volume; for(int i=1;i<=n;i++) { cin>>v[i]>>w[i]; } for(int i=1;i<=n;i++) { for(int j=1;j<=volume;j++) //当前背包容量j { if(j<v[i]) dp[i][j]=dp[i-1][j]; else dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i]); //装了之后容量-v[i],价值增加w[i]; } } for(int i=0;i<=n;i++) { for(int j=0;j<=volume;j++) { cout << dp[i][j] << ' '; } cout<<endl; } cout<<dp[n][volume]; return 0; }
#include<iostream> using namespace std; #include <algorithm> int main() { int w[5] = { 0 , 2 , 3 , 4 , 5 }; //商品的体积2、3、4、5 int v[5] = { 0 , 3 , 4 , 5 , 6 }; //商品的价值3、4、5、6 int bagV = 8; //背包大小 int dp[5][9] = { { 0 } }; //动态规划表 for (int i = 1; i <= 4; i++) { for (int j = 1; j <= bagV; j++) { if (j < w[i]) dp[i][j] = dp[i - 1][j]; else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]); } } //动态规划表的输出 for (int i = 0; i < 5; i++) { for (int j = 0; j < 9; j++) { cout << dp[i][j] << ' '; } cout << endl; } return 0; }
那么我们继续讨论这个二维矩阵到底代表的是什么:
-
第一点不重不漏
- (i,j)集合所表示的是前i个物品,且总体积不超过j的选择方法集合
- 集合当中每一个方案的最大价值max
- dp[n][m] 所有物品,总体积不超过最大限制体积的最大值
- 参考AcWing 2. 01背包问题(闫氏DP分析法) - AcWing