01背包问题——贪心+DP



在8月18号参加了华为的优招机试,三道编程题,前两道难度不算很大,第一题很简单,第二题是经典的01背包问题,小偷偷东西,顺着这个机会也总结一下这个01背包问题,对于题目的描述一开始是凭记忆写的,后来在牛客网上看到了这个面试的题目,应该是对的,不过有小的区别也不影响题目的分析和编程实现。
  
  这题目是一个典型的贪心算法的题目,最基础的算法有几种
  
⑴贪心策略:选取价值最大者。
⑵贪心策略:选取重量最小。它的反例与第一种策略的反例差不多。
⑶贪心策略:选取单位重量价值最大的物品。
⑶贪心策略的改进:对于单位重量价值一样的,则优先选择重量小的!(相对最优)
但是这些情况都可以举出不符合条件的反例。

下面将结合动态规划提出一种最好的解决办法,也很最常见的解决办法,局部最优。

考题说明

题目描述

小偷来到了一个神秘的王宫,突然眼前一亮,发现5个宝贝,每个宝贝的价值都不一样,且重量也不一样,但是小偷的背包携带重量有限,所以他不得不在宝贝中做出选择,才能使偷到的财富最大,请你帮助小偷计算一下。

输入描述:

宝贝价值:6,3,5,4,6
宝贝重量:2,2,6,5,4
小偷背包容量:10

输出描述:

偷到宝贝的总价值:15

示例1

输入

6,3,5,4,6

2,2,6,5,4

10

输出

15

代码实现

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	//之所以设置长度是六,我是为了和底下的6*11(第一行和第一列均为0)
	//的二维数组对应,第一个元素设置为0
	int value[6];//价值数组
	int weight[6];//重量数组
	
	int m;
	scanf("%d,%d,%d,%d,%d",&value[1],&value[2],&value[3],&value[4],&value[5]);
	scanf("%d,%d,%d,%d,%d",&weight[1],&weight[2],&weight[3],&weight[4],&weight[5]);
	cin>>m;
	
	//定义一个二维数组 dp[][],存放总价值
	int **dp;
	dp = new int*[6]; //定义了6行
	
	//这里是动态申请数组,每一行都是定值。其实也可以直接一开始就申请dp[6][11],然后memset(A,0,sizeof(A)),全部初始化为零;
	for(int i =0;i<=5;i++)
	{
		dp[i] = new int [m+1];//每一行都是在背包容量从0开始,到m,容量是m+1 
	}
	
	//初始化第一列为0
	for(int i =0;i<=5;i++)
	{
		dp[i][0] = 0;
	}
	//初始化第一行为0
	for(int j = 0;j<=m;j++)
	{
		dp[0][j] = 0;
	}
	
	//执行动态规划,自小到大计算,生成,value表
	for(int i = 1;i<=5;i++)
	{
		for(int j = 1;j<=m;j++)
		{
			if(j<weight[i])
			{
				//当背包的重量小于当前物品的重点时,则沿用上一行的value值
				dp[i][j] = dp[i-1][j];
			}
			else
			{
				//否则便进行计算,分两种情况,不包含i和包含i, 非一既零原则。
				//计算两种情况中较大的值,物品数从少到多进行计算
				//因为类似于斐波那契数列,前面会用到后面的值,故采用自底向上的计算方法
				//计算公式:F[i][j] = max(F[i-1][j],F[i-1][j-w[i]]+v[i])
				dp[i][j] = max(dp[i-1][j],dp[i-1][j - weight[i]]+value[i]);
			}
		}
	}
	cout<<dp[5][m]<<endl;
	return 0;
	
}

算法分析

基本思路是将该问题转化为子问题进行求解。考虑N件物品在限重M的背包下可选择的最大价值F[N][M],这个问题可以分解成两种情况来考虑:这是一个非黑即白的问题,因为一个物品只存在两种状态,放入背包没有放入背包.

  1. N1不放入背包,则问题转化为F[N-1][M],N1不放入背包,则物品数减一
  2. N1放入背包,问题转化为value[N1]+f[N-1][M-weight[N1]],N1放入背包,则背包承重减少。

原问题的解取上面两种情况中的最大值。既F[N][M] = max{F[N-1][M], (F[N-1][M-weight[N1]+value[N1]))}。接下来问题又变成了求解F[N-1][M]和 F[N-1][M-weight[N1]两个子问题。然后一直类推到一个物品时。以此类推的话我们解决原始问题需要子问题的解。我们需要先计算子问题,自底向上求解。解决顺序如下表。从左到右,从上到下计算。货品的顺序不影响最后的计算结果。

表格分析

此表格是按照计算的方向来写的。计算的方法是一样的,分析方法也是一样,在此题中没有要求按序输出选中的物品,故输入顺序并没有影响。
  第一行和第一列初始化为0,则可以直接代入公式计算。
  
  第二行为只放入第一件物品,背包的最优值
  第三行为只放入前两件物品,背包的最优值
  …
  依次类推,最后的F[6][11]即为最优值。

货品weightvalue012345678910
00000000000000
12600666666666
22300669999999
36500669999111114
454006699910101314
5460066991212151515

还有一个动态规划的详细解读博客动态规划扔鸡蛋!

  • 15
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值