背包问题

有一个小偷,跑到一户人家去偷东西;
小偷可以偷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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值