DP 01背包问题

问题建模:

	给定一个大小为 j 的背包,现在有一堆商品:每个商品的size   和  value
	现在需要给背包里装东西:  目的是:装的东西的价值要尽可能最大。

	现在问你,怎么装?

问题 分析:
这种问题:乍一看好像很棘手,size 大的value 可能很小。却大大浪费了空间。

	细细分析: 其实是一种动态选择问题:即动态规划:

核心:
每次遇到一个商品 ,经过衡量选择: 放入? 不放入?背包
不放入:肯定是由于空间导致
放入: 1 空间充足,直接放入,
2 空间不充足,需要衡量是否要取出一些,再放入该商品。(衡量标准:保证value最大)

那么 状态转移方程就来了:

F(i, j) 表示 当前value —>很明显,用二维数组存储的 value

因为数组下标从0开始:所以用F(i-1, j-1)来表示
i: 表示第 i 个商品
j: 表示当前背包空间大小为 j

F(i-1, j-1) = max (F(i-1, j-1), F(i-1, j- A[i-1]) + V[ i-1])//V 代表value

在这里插入图片描述
在这里插入图片描述

一目了然: 计算时开辟二维数组, 没来到一个商品前进行空间变化的各种衡量 。

最终得到数组的最后一个元素就是最大的。 (类似于动态贪心)。 DP是贪心的father·~

//A :商品空间大小      V:商品价值大小
int backPack(int m, vector<int>&A, vector<int> & V)
{
  int n =A.size();//n:商品个数      m:背包大小
  vector<vector<int>> maxValue(n+1,vector<int>(m+1,0));
  for(int i=1; i<=n; ++i)//第i 个商品品
  {
    for(int j=1; j<=m; ++j)//有j个空间
    {
     //因为我们下标从1开始,所以实际下表应该从i-1开始
    
    	//判断当前商品空间是否大于总空间
      if(A[i-1] > j)//当前商品空间大于背包空间了  返回上一个商品对应空间的最大价值
        maxValue[i][j] = maxValue[i-1][j];
        
      else//否则,:  1 不腾空间,不放   2  先腾空间,再放入
      //maxValue[i-1][j]:剩余不腾空间
        maxValue[i][j] = max(maxValue[i-1][j],  maxValue[i-1][j-A[i-1]] + V[i-1]);
    }
  }
  return maxValue[n][m];//返回商品n,空间j时对应的最大value
  //注意:这个n并不代表n个商品都选选取了,只是说明,选择时来到过n
  //同理,m也不是说m个空间全装满了,只是说明计算到了m这个地方的最大value
}

优化

注意分析 : 当我们计算时,只需要前一行的值,其它行的值都不用了,

那么我们可以优化一下: 只申请一维数组:

注意这行代码:⚠️
 maxValue[j] = max(maxValue[j], maxValue[j-A[i-1]] + V[i-1]);

一维数组时:这里存在更新问题 : 当前商品的选择与否,受到上一行商品对应数据的影响,而我们只有一行,那么怎么体现上一行呢?

上一 行的数据其实就是没有更新之前的数据,我们正向走的话,ke neng会导致将本行数据当作上一行了,
解决策略: 反向走,前边的数据肯定没被更新

//A :商品空间大小      V:商品价值大小
int backPack(int m, vector<int>&A, vector<int> & V)
{
  int n =A.size();//n:商品个数      m:背包大小
  vector<int> maxValue(m+1,0));
  for(int i=1; i<=n; ++i)//第i 个商品品
    for(int j=m; j>=V[i]; --j)//有j个空间
        maxValue[j] = max(maxValue[j], maxValue[j-A[i-1]] + V[i-1]);
  return maxValue[m];//返回最大空间时的value
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值