一维化01背包(详细)

本文详细解释了一维化01背包问题中的动态规划方法,通过将二维dp数组转换为一维,讨论了不同的遍历顺序和如何在没有[i]维度时找到最优解。代码示例展示了如何使用C++实现一维dp数组求解背包问题。
摘要由CSDN通过智能技术生成

http://t.csdnimg.cn/P7R3G

之前我们介绍了01背包,但是dp数组是二维化的,现在我们需要将其变成一维数组,如果已经对二维化的01背包十分了解了,那么理解一维化的dp数组也不是问题。

目录

分析

 遍历顺序

原二维遍历

一维倒序遍历

代码


分析

我们再拿这个表格:

 

图中i为物品序号,value[i]为物品价值,weight[i]为物品重量。

j为背包大小。

dp数组的推导公式是

dp[i][j]=max(dp[i-1][j-1],value[i]+dp[i-1][j-weight[i]]);

即在选与不选中抉择,如果不选,那么总价值就是当前大小背包的原价值(即只考虑当前物品前的所有物品),

如果选,那么总价值就是该物品价值加上剩余空间背包的最优解。

那我们不妨将dp数组想象成一个滚动的一维数组,每次对一个物品进行各种大小背包的分析,然后再对下一个物品进行各种大小背包的分析,每次均保留最优解。

这样下来,这个一维化的数组就是对所有已分析过的物品的最优解了。

 遍历顺序

原二维遍历

我们可以发现,在原二维数组里,我们是在dp[i-1][j-1]value[i]+dp[i-1][j-weight[i]]中选取最大值,因为不考虑当前物品,所以我们是在dp[i-1]范围内选取,即在当前物品前面的所有已分析物品中。

一维倒序遍历

在一维数组里,我们没有[i]这个维度,那我们如何找到“当前物品前面的所有已分析物品中”这个范围呢?

答案很简单,我们的一维数组是考虑完前面所有物品的最优解,本身就是“当前物品前面的所有已分析物品中”的范围,所以我们只需要在原数值和新数值中抉择即可:

dp[j]=max(dp[j],value[i]+dp[j-weight[i]]);

但是如果我们按照背包从小打大的顺序遍历,即按照从0到背包最大容量的顺序写的话,前面的较小背包就会考虑进当前物品,当后面的背包需要dp[j-weight[i]]的时候,就算两遍当前物品i,所以我们需要按背包容量从大到小遍历。

这时就会有疑问了,那如果按照背包容量从大到小遍历,那遇到dp[j-weight[i]]的情况,需要找小背包怎么办,这时候就需要回过头想想,我们的一维dp数组保存的就是考虑了当前物品前所有物品的最优解,就是我们需要的dp[j-weight[i]]

代码

#include <iostream>
#include <vector>
using namespace std;

class Solution
{
public:
    int bag(vector<int>& weight,vector<int>& value,int bag)
    {
        //初始化
        vector<int> dp(bag+1,0);
        //dp[j]=max(dp[j]+value[i]+dp[j-weight[i]]);
        //初始化
        dp[0]=0;
        //遍历顺序
        for(int i=0;i<weight.size();i++)
        {
            for(int j=bag;j>=0;j--)
            {
                /*if(weight[i]>j)
                {
                    dp[j]=dp[j];
                }*/
                if(weight[i]<=j)
                {
                    dp[j]=max(dp[j],value[i]+dp[j-weight[i]]);
                }
                cout<<dp[j]<<' ';
            }
            cout<<endl;
        }
        return dp[bag];
    }
};

int main() {
    std::cout << "Hello World!\n";
    vector<int> weight={1,3,4};
    vector<int> value={15,20,30};
    int bag=4;
    Solution so;
    cout<<so.bag(weight, value, bag);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值