01背包问题相关优化大全(二维到一维)

下面是普通版本的01背包代码!

int dp[105][1005];
    for(int i=1;i<=m;i++)
        for(int j=t;j>=0;j--)
        {
            if(j>=w[i])
            {
                dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]);
            }else{
              dp[i][j]=dp[i-1][j];
            }
        }

滚动数组优化二维01背包

我们可以看到dp数组需要很大,至少超过2行!
那么我们想一想可不可减少行数呢?

首先我们知道,d[i][j]的值只和它的上一种状态有关,即dp[i-1][j],也就是第i行的dp值,只与第i-1行有关,我们通过这条性质,可以将dp数组减少到两行即可,也就是滚动数组优化01背包!

如果不理解建议看下,尤其是那个表格01背包

那么如何做到呢?

很简单,我们在更新第i行数据时,之需要将原来的i-2行覆盖掉,根据i-1行,更新数据!
也就时每次i%2,如果i为奇数那么第i行数据写在第1行,i为偶数第i行数写在第0行!
最终输出的结果就是dp[m][v]

我们看下代码!

#include <iostream>

using namespace std;
int w[105],v[105];
int dp[2][1005];//滚动数组优化01背包
int main()
{
    int t,m,res;
    scanf("%d%d",&t,&m);
    //读入数据
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&w[i],&v[i]);
    }
    for(int i=1;i<=m;i++)
    {
        for(int j=t;j>=0;j--)
        {
            if(j>=w[i])
            {   //每次%2
                dp[i%2][j]=max(dp[(i-1)%2][j-w[i]]+v[i],dp[(i-1)%2][j]);
            }else{
              dp[i%2][j]=dp[(i-1)%2][j];
            }
        }
    }
    //输出最后一个数据
    printf("%d",dp[m%2][t]);

    return 0;
}

一维01背包优化

最后这个优化是01背包问题空间的终极优化,原理也是十分简单,我用图例给大家讲解!

大家先明确一个概念:“时间差”

我们在第i行,从重量最重的开始遍历,也就是从后向前遍历!
这样遍历有什么好处呢?
答案就是,可以打"时间差",用一行解决问题!
上图!!!

在这里插入图片描述

大家仔细看图片中的注释!

还有一个小问题,我后面的元素可以借助前面的元素保证都更新,那么我前面的元素呢?
实际上,当前重量w[i]如果小于当前物品的重量时,那么它和上一行的值是相同的我们不需要更新!
大家看图!
假设i=3时,当前物品重量为4!
我们看第3行,重量从0~3都不需要更新,直接从上一行拿过来就可以了!
在这里插入图片描述

想必大家已经理解了,我说的时间差这个概念,下面附上代码!!

#include <iostream>

using namespace std;
int w[105],v[105];
int dp[1000];//一维优化
int main()
{

    int t,m,res;
    scanf("%d%d",&t,&m);
    //读入数据
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&w[i],&v[i]);
    }
    for(int i=1; i<=m; i++)
        for(int j=t; j>=w[i]; j--)
        {
            dp[j]=max(dp[j-w[i]]+v[i],dp[j]);
        }
    printf("%d",dp[t]);
    return 0;
}

这道题是采药的题,我把链接给大家,大家可以跑一跑!
采药洛谷
谢谢观看,如果对你有帮助,多多点赞支持!

  • 38
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值