动态规划-0/1背包

1. 题目描述

    有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值。已知对于一件物品必须选择取(用1表示)或者不取(用0表示),且每件物品只能被取一次(这就是“0-1”的含义)。 求放置哪些物品进背包,可使这些物品的重量总和不超过背包容量,且价值总和最大。
样例 1:
    输入: m = 10, A = [2, 3, 5, 7], V = [1, 5, 2, 4]
    输出: 9
    解释: 装入 A[1] 和 A[3] 可以得到最大价值, V[1] + V[3] = 9
样例 2:
    输入: m = 10, A = [2, 3, 8], V = [2, 5, 8]
    输出: 10
    解释: 装入 A[0] 和 A[2] 可以得到最大价值, V[0] + V[2] = 10

2. 思路分析

    可以先这样考虑,当背包容量为1时,如何放置物品才能使背包中价值最大;同样当背包容量为2时,如何放置能使背包中价值最大,以此类推,直到背包容量为10。此时我们需要维护一张二维表max_value[i][j],其中横坐标i表示物品,纵坐标表示背包容量(0<=j<=10)。
状态:
    F(i, j): 前i个物品放入大小为j的背包中所获得的最大价值
状态递推:
    对于第i个商品,有一种例外,装不下,两种选择,放或者不放
    如果装不下:此时的价值与前i-1个的价值是一样的F(i,j) = F(i-1,j)
    如果可以装入:需要在两种选择中找最大的F(i, j) = max{F(i-1,j), F(i-1, j - A[i]) + V[i]}
    F(i-1,j): 表示不把第i个物品放入背包中, 所以它的价值就是前i-1个物品放入大小为j的背包的最大价值。
    F(i-1, j - A[i]) + V[i]:表示把第i个物品放入背包中,价值增加V[i],但是需要腾出j - A[i]的大小放第i个商品。
初始化:
    第0行和第0列都为0,表示没有装物品时的价值都为0。F(0,j) = F(i,0) = 0
返回值:
    F(n,m)

3. 实例

    对于承重为m=5的背包有:
重量和价值表
    根据上面的思路可以得到下面这个二维递推表:
在这里插入图片描述
    因此最优解F(4,5)=37.

4. 代码

//多增加一行一列:行为0表示没有物品乐园放入  列为0表示背包没有大小 所有的物品都不能放入
class Solution {
public:
	int backPackII(int m, vector<int> &A, vector<int> &V) {
		// write your code here
		if (A.empty() || V.empty() || m <0)
		{
			return 0;
		}
		int row = A.size() + 1;//行数
		//列数:m+1-----因为增加了0列
		int col = m + 1;
		vector<vector<int>>max_value(row, vector<int>(col));
		for (int j = 0; j < col; ++j)
		{
			max_value[0][j] = 0;
		}
		for (int i = 1; i < row; ++i)
		{
			max_value[i][0] = 0;
		}
		for (int k = 1; k < row; ++k)
		{
			for (int l = 1; l < col; ++l)
			{
				//第k个商品在A中对应的索引为k-1: k从1开始
				//如果第k个商品大于l,说明放不下, 所以(k,l)的最大价值和(k-1,l)相同
				if (l<A[k - 1])//放不进去
				{
					max_value[k][l] = max_value[k - 1][l];
				}
				else 
				{
					//如果可以装下,分两种情况,装或者不装
					//如果不装,则即为(k-1, l)
					//如果装,需要腾出放第k个物品大小的空间: l - A[k-1],装入之后的最大价值即为(k - 1, l - A[k - 1]) + 第k个商品的价值V[k - 1]
					//最后在装与不装中选出最大的价值
					max_value[k][l] = max(max_value[k - 1][l], (max_value[k - 1][l - A[k - 1]] + V[k - 1]));
				}
			}
		}
		return max_value[row - 1][col - 1];
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值