您的位置:首页 > 其它

背包问题

2016-01-07 14:39 183 查看
有一个小偷,跑到一户人家去偷东西;

小偷可以偷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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: