动态规划的总结

背包问题

01背包

01背包就是将那个物品存放在背包中,存放就是1,不存放就是0,每种物品只有一个

暴力解法

在这里插入图片描述
在这里插入图片描述
i ==0 我们穷举出当要存放0号物品时,容器大小要是为 j = 0、1、2、3、4,dp[i][j] 的最大大小
i == 1 穷举出存放[0,1]号物品时,容器中大小要为 j = 0、1、2、3、4,dp[i][j]最大大小
i = = 2 穷举出存放[0,2]号物品时,容器大小为j = 0、1、2、3、4,dp[i][j] 最大大小

动态规划

状态转移方程
dp[i][j] 表示从[0,i]中任意选取物品,放到背包容器为j里面的最大价值

不放物品i的时候 dp[i-1][j] 表示从0~i-1 件物品中任意选择,存放在容器为j的包中
一定放物品i dp[i-1][j-weight[i]] + value[i] 表示从0~i-1 件物品中任意选择,存放到容器为j -weight[i] 的包中空出一个物品i的位置,再额外将物品i存放进包中

dp[i][j] = max( dp[i-1][j],dp[i-1][j-weight[i]+value[i]] 选择二者中最大的

初始化:
可以看出当i = 0,j = 0,无法套公式计数

当i = 0 dp[0][j] 表示将0号物品存放到容器为j的容器中
要是容器大小小于0号物品大小,也就是j < weight[0],那么dp[0][j] = 0
要是容器大小大于0号物品大小,dp[0][j] = value[0]

当j = 0,也就是dp[i][0] 背包容器为零 dp[i][0] = 0
在这里插入图片描述

完整代码

void test_2_wei_bag_problem1()
{
  vector<int> weight = {1,3,4};
  vector<int> value = {15,20,30};
int bagweight = 4;
//二维数组
vector<vector>int> >dp(weight.size(),vector<int>(bagweight +1,0))//全部初始化为0

//初始化
for(int j = weight[0]; j <= bagweight;j++)//容器j只要大于0号物品的容积都是vaule[0]
{
   dp[0][j] = value[0]
}
//遍历
for(int i = 1; i < weight.size();i++)//遍历物品
{
  for(int j = 0; j <= bagweight;j++)//遍历背包容器
  {
    if(j < weight[i]) dp[i][j] = dp[i-1][j];//当前容器放不下,物品i
    else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
      
  }
   cout << dp[weight.size() - 1][bagweight] << endl;//输出表
}

深度解析:

1、物品分次放
每次存放物品看成是对五个空间进行一次操作
2、空间划分
我们五个账号对应的是一个空间,但是权限不同,可以使用的空间不同
我们将物品一个个放,分三层,属于叠加,本层都是由上一层的基础上得到的
创建出物品1、2、3各层对应五个不同空间的元素
第一层:
存放物品o到五个不同空间中

第二层
对上面五个空间,看看要不要存放物品1

第三层
对上面的五个空间看看要不要存放物品2

怎么判断那种放法生成的dp值最大

if(j < weight[i]) dp[i][j] = dp[i-1][j];//本次物品,空间无法存放

  else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
  dp[i-1][j] 抄下就是上一层dp,不次不存放本次物品 
  dp[i-1][j-weight]   找到上一层中存放了上一层元素并且使用的空间比较小的,然厚将本层元素插入那个空间

将二维数组转换为一维数组
在这里插入图片描述

将二维数组转换成为一维数组,将多行的数组更新与一行,这样看起来就像是一行数据在滚动

我们当前层是由上一层推导出来的,我们要是将当前层数据直接写在上一层,这样就是直接覆盖上一层数据,就像只有一行数据一直在刷新

dp[j] 容器为j的背包能装的最大价值为dp[j]

为什么我们要先遍历物品再遍历背包?
因为我们要将背包倒序遍历
为什么背包大小是从大到小倒序遍历?
防止小物品多次放入,我们是每次物品遍历一次

dp

void test_1_wei_bag_problem() {
    vector<int> weight = {1, 3, 4};
    vector<int> value = {15, 20, 30};
    int bagWeight = 4;

    // 初始化
    vector<int> dp(bagWeight + 1, 0);
    for(int i = 0; i < weight.size(); i++) { // 遍历物品
        for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);//前一个是不放物品i,第二个是指定存放物品i
        }
    }
    cout << dp[bagWeight] << endl;
}

int main() {
    test_1_wei_bag_problem();
}

深度解析:
这和上面一样,不同是每次进行的操作记录的结果会覆盖上一次的结果

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值