前引
博主现在在面临着七门考试,但今晚得补一个算法作业,在此记录一下解决思路。
一.问题描述
有 N 件物品和一个最多能被重量为 W 的背包。第 i 件物品的重量是 weight[i],得到的价值是 value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
这里我们把问题具体化:有四件商品,价值依次为 1500,2000,2000,3000,对应的重要依次为1,1,3,4,背包容量为4.
二.解决思路
动态规划: 先解决子问题,再逐步解决大问题
我们的目标是求出在有四件商品可选的情况下,容量为4的背包能装入的最大价值。那么这个问题的子问题是:在有1~4个商品可选的情况下,容量1 ~ 4的背包能装入的最大价值。我们可以表示为以下表格
容量1 | 容量2 | 容量3 | 容量4 | |
---|---|---|---|---|
(1500,1) | 1500 | 1500 | 1500 | 1500 |
(2000,1) | 2000 | 3500 | 3500 | 3500 |
(2000,3) | 2000 | 3500 | 3500 | 4000 |
(3000,4) | 2000 | 3500 | 3500 | 4000 |
显然表格右下角的数值就是我们最终的答案
按照先遍历物品,再遍历背包重量的思路,具体的求解思路应该是:先求出一件商品可选情况下,背包总 1 ~ 4的最大价值,再求出二件商品可选…逐步求出四件商品可选时,背包容量为4的最大价值
三.为什么先解决子问题可以最后解决大问题?
对于表格的每一项,在第一行仅可选一件商品情况下,背包价值在能装下该商品的情况下,最大价值为该商品价值
if (i == 0 && weight[0]<=j) // i:commodity serial number , j:bagweight
dp[i][j] = value[0]; // Only one item can be selected
对于表格的其余项,填入的值只有两种选择
-
当前商品行的价值 + 背包剩余容量可装下的最大价值
-
不选择装入当前行商品,背包内物品最大价值不变
两者取max
显然,当背包容量小于当前商品重量时,必然只能选择第二个
for (int i = 1; i < cdyNum; i++) // commodity serial number
for (int j = 1; j <= bagWeight; j++) // bagweight
{
if (j < weight[i])//bagWeight is less than the current row weight, the maximum value will not change
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = max(dp[i - 1][j], value[i] + dp[i - 1][j - weight[i]]);
}
自此我们可以看出,子问题为我们提供了一个信息:背包剩余容量可装下的最大价值,进而我们才可以确定两个选择的值,进而选出最大价值。
四. C++
代码中对表格的初始化略显多余,对除第1行第0列的赋值以外均没有必要,但为了避免变量出现不确定值,我还是选择对该部分初始化为0。
void Solution()
{
int bagWeight = 4;
int cdyNum = weight.size(); //number of commondity
vector<int>weight { 1,1,3,4};
vector<int>value{ 1500,2000,2000,3000};
vector<vector<int>> dp(cdyNum,vector<int>(bagWeight + 1));// Two-dimensional array
//initial
for(int i = 0;i<cdyNum;i++) // commodity serial number
for (int j = 0; j <= bagWeight; j++) // bagweight
{
if (j == 0) // bagWeight = 0 ,so total value = 0
dp[i][j] = 0;
else if (i == 0 && weight[0]<=j)
dp[i][j] = value[0]; // Only one item can be selected
else
dp[i][j] = 0;
}
// dynamic programming
for (int i = 1; i < cdyNum; i++) // commodity serial number
for (int j = 1; j <= bagWeight; j++) // bagweight
{
if (j < weight[i])//bagWeight is less than the current row weight, the maximum value will not change
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = max(dp[i - 1][j], value[i] + dp[i - 1][j - weight[i]]);
}
//result
cout <<"the maximum value: "<< dp[cdyNum - 1][bagWeight] << endl;
}
int main()
{
Solution();
}