有一个小偷,跑到一户人家去偷东西;
小偷可以偷6样物品,重量分别为:weight[6] = {1,2,2,6,5,4},对应的价值分别为value[6] = {1,6,3,5,4,6};
小偷只背了一个最大容量为10的包;
问:小偷可以偷走的最大价值是多少?
解题思路:
1).找最贵的偷;
2).找装的最多(最轻)的偷;
3).动态规划求得最优值。
动态规划的原理就是:根据前一次的“最优值”计算当前的“最优值”。
具体步骤:
1. 用一个matrix[num][capacity+1]代表背包中一定物品、一定重量的价值。
num为特定物品,capacity为物品的重量从0到10+1(从0开始是为了便于矩阵下标0的统计)。
这个背包初始情况下为0,如下:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 0 0 0 0 0 0 0 0 0 0
(6)2 0 0 0 0 0 0 0 0 0 0 0
(3)2 0 0 0 0 0 0 0 0 0 0 0
(5)6 0 0 0 0 0 0 0 0 0 0 0
(4)5 0 0 0 0 0 0 0 0 0 0 0
(6)4 0 0 0 0 0 0 0 0 0 0 0
2. 在背包中按物品顺序依次放入,首先放入物品1,物品1对应的价值是1;
在这里,有1个逻辑:物品1在重量0<1<10的情况下,其价值都为1。
如下:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 0 0 0 0 0 0 0 0 0 0
(3)2 0 0 0 0 0 0 0 0 0 0 0
(5)6 0 0 0 0 0 0 0 0 0 0 0
(4)5 0 0 0 0 0 0 0 0 0 0 0
(6)4 0 0 0 0 0 0 0 0 0 0 0
3. 然后放入物品2;
在这里,有3个逻辑:
1).物品2在 2<2<10的情况下,其价值都为6;
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 0 6 6 6 6 6 6 6 6 6
2).在累加重量的基础上累加前一次的价值;
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 0 6 7 7 7 7 7 7 7 7
3).用前一次大的价值取代当前小的价值(补充物品1在重量1时的价值);
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
本次填值之后,结果如下:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 0 0 0 0 0 0 0 0 0 0
(5)6 0 0 0 0 0 0 0 0 0 0 0
(4)5 0 0 0 0 0 0 0 0 0 0 0
(6)4 0 0 0 0 0 0 0 0 0 0 0
4. 再放入第3个物品2;
在这里,有3个逻辑:
1).物品2在 2<2<10的情况下,其价值都为3;
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 0 3 3 3 3 3 3 3 3 3
2).在累加重量的基础上累加前一次的价值;
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 0 3 3 9 10 10 10 10 10 10
3).用前一次大的价值取代当前小的价值;
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 1 6 7 9 10 10 10 10 10 10
本次填值之后,结果如下:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 1 6 7 9 10 10 10 10 10 10
(5)6 0 0 0 0 0 0 0 0 0 0 0
(4)5 0 0 0 0 0 0 0 0 0 0 0
(6)4 0 0 0 0 0 0 0 0 0 0 0
后续填值过程与前一次成递归关系,最终结果如下:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 1 6 7 9 10 10 10 10 10 10
(5)6 0 1 6 7 9 10 10 10 11 12 14
(4)5 0 1 6 7 9 10 10 10 11 13 14
(6)4 0 1 6 7 9 10 12 13 15 16 16
我们可以看到小偷可以偷到最贵重的价值为:16
小结:
1.一定要在纸上画,多画几遍,理清逻辑;
2.写代码时,不断调试,用计算机理解的方式(逻辑)表达出来。
小偷可以偷6样物品,重量分别为:weight[6] = {1,2,2,6,5,4},对应的价值分别为value[6] = {1,6,3,5,4,6};
小偷只背了一个最大容量为10的包;
问:小偷可以偷走的最大价值是多少?
解题思路:
1).找最贵的偷;
2).找装的最多(最轻)的偷;
3).动态规划求得最优值。
动态规划的原理就是:根据前一次的“最优值”计算当前的“最优值”。
具体步骤:
1. 用一个matrix[num][capacity+1]代表背包中一定物品、一定重量的价值。
num为特定物品,capacity为物品的重量从0到10+1(从0开始是为了便于矩阵下标0的统计)。
这个背包初始情况下为0,如下:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 0 0 0 0 0 0 0 0 0 0
(6)2 0 0 0 0 0 0 0 0 0 0 0
(3)2 0 0 0 0 0 0 0 0 0 0 0
(5)6 0 0 0 0 0 0 0 0 0 0 0
(4)5 0 0 0 0 0 0 0 0 0 0 0
(6)4 0 0 0 0 0 0 0 0 0 0 0
2. 在背包中按物品顺序依次放入,首先放入物品1,物品1对应的价值是1;
在这里,有1个逻辑:物品1在重量0<1<10的情况下,其价值都为1。
如下:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 0 0 0 0 0 0 0 0 0 0
(3)2 0 0 0 0 0 0 0 0 0 0 0
(5)6 0 0 0 0 0 0 0 0 0 0 0
(4)5 0 0 0 0 0 0 0 0 0 0 0
(6)4 0 0 0 0 0 0 0 0 0 0 0
3. 然后放入物品2;
在这里,有3个逻辑:
1).物品2在 2<2<10的情况下,其价值都为6;
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 0 6 6 6 6 6 6 6 6 6
2).在累加重量的基础上累加前一次的价值;
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 0 6 7 7 7 7 7 7 7 7
3).用前一次大的价值取代当前小的价值(补充物品1在重量1时的价值);
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
本次填值之后,结果如下:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 0 0 0 0 0 0 0 0 0 0
(5)6 0 0 0 0 0 0 0 0 0 0 0
(4)5 0 0 0 0 0 0 0 0 0 0 0
(6)4 0 0 0 0 0 0 0 0 0 0 0
4. 再放入第3个物品2;
在这里,有3个逻辑:
1).物品2在 2<2<10的情况下,其价值都为3;
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 0 3 3 3 3 3 3 3 3 3
2).在累加重量的基础上累加前一次的价值;
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 0 3 3 9 10 10 10 10 10 10
3).用前一次大的价值取代当前小的价值;
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 1 6 7 9 10 10 10 10 10 10
本次填值之后,结果如下:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 1 6 7 9 10 10 10 10 10 10
(5)6 0 0 0 0 0 0 0 0 0 0 0
(4)5 0 0 0 0 0 0 0 0 0 0 0
(6)4 0 0 0 0 0 0 0 0 0 0 0
... ...
后续填值过程与前一次成递归关系,最终结果如下:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1)1 0 1 1 1 1 1 1 1 1 1 1
(6)2 0 1 6 7 7 7 7 7 7 7 7
(3)2 0 1 6 7 9 10 10 10 10 10 10
(5)6 0 1 6 7 9 10 10 10 11 12 14
(4)5 0 1 6 7 9 10 10 10 11 13 14
(6)4 0 1 6 7 9 10 12 13 15 16 16
我们可以看到小偷可以偷到最贵重的价值为:16
小结:
1.一定要在纸上画,多画几遍,理清逻辑;
2.写代码时,不断调试,用计算机理解的方式(逻辑)表达出来。
具体代码如下:
#include<iostream>
using namespace std;
const int num = 6;//物品数量
const int weight[num] = {1,2,2,6,5,4};//物品的重量
const int value[num] = {1,6,3,5,4,6};//物品对应的价值
const int capacity = 10; //背包的容量
//背包中一定物品、一定重量的价值,默认全为0;num为特定物品,capacity为物品的重量从0到10+1(从0开始是为了便于矩阵下标0的统计)。
int matrix[num][capacity+1]= {0};
void knapsackProblem()
{
//第1个for,对应matrix的列,从第0个物品开始统计
for(int i_n = 0; i_n<num; i_n++)
{
//第2个for,对应matrix的行,从重量0到10开始统计
for(int j_w = 0; j_w<=capacity; j_w++)
{
//对于第1个物品,直接输入
if(i_n==0)
{
//物品1在重量0<1<10的情况下,其价值都为1;重量0默认价值为0。
if(weight[i_n]<=j_w)
matrix[i_n][j_w] = value[i_n];
}
else
{
//除第1个物品外,判断:1.当前物品的重量范围;2.前一次的“最优价值”与当前的“价值”比。
if((weight[i_n]<=j_w) || (matrix[i_n][j_w]<matrix[i_n-1][j_w]))
{
int supplement_w = j_w-weight[i_n];
//先判断是否根据前一次的“最优值”计算当前的“最优值”。
if(supplement_w>=0)
{
//当前重量价值 + 补充重量价值
matrix[i_n][j_w] = value[i_n]+matrix[i_n-1][supplement_w];
}
//当当前的“价值”小于前一次的“最优价值”,被前一次取代。
if(matrix[i_n][j_w]<matrix[i_n-1][j_w])
{
matrix[i_n][j_w]=matrix[i_n-1][j_w];
}
}
}
}
}
}
int main()
{
knapsackProblem();
//打印出矩阵
for(int i =0; i<num;i++)
{
for(int j = 0; j<=capacity; j++)
{
cout<<matrix[i][j]<<" ";
}
cout<<endl;
}
<span style="white-space:pre"> </span>return 1;
}