最简单直观详细的理解 背包问题 的一维解法 动态规划

关于背包问题一维解法,网上一堆各种讲解资料,笔者在参考了很多资料后,总结出了一份较简单直观便于理解的一维解法的讲解。

老规矩,我们还是从题切入,先看题目要求:

本文只讲解背包问题的一维解法,关于背包问题动态规划的二维解法,详见上一篇文章:最简单直观详细的理解 背包问题 的一维解法 动态规划_一维背包问题_Bule Guy的博客-CSDN博客

首先,对于背包问题的二维解法,对于f[i][j],我们可以得到一个二维表格

然后根据二维公式f[i][j]=max{ f[i-1][j], f[i-1][j-v[i]]+w[i] },我们可以填满该二维表格。

该办法的缺点就是,按照题意我们只需要装满包的容量那个结果,即f[N][V],但是我们观察二维表格数据可以得出一个非常直观的规律,我们填二维表格的下一行的数据,是需要二维表格上一行数据才能计算出来的。

所以我们需要用二维数组将前面所有数据计算出来f[N][V]。

但是因为我们只需要前一行的数据来计算下一行的数据,那么为了节省空间,我们其实可以只保存当前行和上一行两行数据即可,之前的数据我们用完后直接覆盖掉不就可以了吗?

所以我们可以直接用一维数组进行优化

我们定义一维数组  f[j]:N件物品,背包容量j下的最优解。

此时     f[j]=max(f[j], f[j - v[i]] + w[i])

( 二维时,公式为f[i][j]=max{ f[i-1][j], f[i-1][j-v[i]]+w[i] }  可以参考对比下有什么异同)

另外,还有一点和二维数组不一样的是:一维要采取逆序的方式来循环,为什么呢,

我们举例说明:

假如枚举到:i = 3, j = 8, v[3] = 5, w[3] = 1

二维:dp[3][8] = max(dp[2][8], dp[2][3] + w[3])   此时的dp[2][8]和dp[2][3]都是上一轮的状态值

一维:dp[8] = max(dp[8], dp[3] + w[3])      我们要保证dp[8]和dp[3]都是上一轮的状态值

按照逆序的顺序,一维dp数组的更新顺序为:dp[8], dp[7], dp[6], ... , dp[3]

也就是说,在本轮更新的值,不会影响本轮中其他未更新的值!较小的index对应的状态是上一轮的状态值!

如果按照顺序进行更新,dp[3] = max(dp[3], dp[0] + w[0]),对dp[3]的状态进行了更新,那么在更新dp[8]时,用到的dp[3]
就不是上一轮的状态了,不满足动态规划的要求。

所以代码为:

#include<iostream>
#include<cstring>
#include<algorithm>
 
using namespace std;
const int N=1010;
int n,m;//n个物品,背包容量为m
int f[N];
int v[N],w[N];//物体的体积和价值
int main(){
    cin>>n>>m;
    //输入物体体积和价值
    for(int i=1;i<=n;i++)//数列下标从1开始,而不是0
    {
        cin>>v[i]>>w[i];
    }
    
   for(int i = 1; i <= n; i++) 
    for(int j = m; j >= 0; j--)  //注意这里是逆序
    {
        if(j < v[i]) 
           // f[i][j] = f[i - 1][j];  二维时的做法
            f[j] = f[j];            // 一维优化后,该行自动成立,可省略。
        else    
           // f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]); 二维时的做法
            f[j] = max(f[j], f[j - v[i]] + w[i]);                   // 一维优化后
    }    
    //输出最终结果
    cout<<f[m]<<endl;
    return 0;
    
    
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值