01背包问题

2. 01背包问题 - AcWing题库

AC代码:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;
int w[N],v[N];
int f[N][N]={0};

int main()
{
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>v[i]>>w[i];
    }
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            f[i][j]=f[i-1][j];
            if(j>=v[i])
            f[i][j]=max(f[i-1][j-v[i]]+w[i],f[i][j]);
        }
    }
    cout<<f[n][m];
    return 0;
}

相关解释:

这题是经典动态规划问题,也就是学动态规划必须会的题。这里要理解递推,也就是理解状态的转移。这里我们首先要进行状态表示,f[i][j]表示的是背包体积为j,从前i个物品中选所能获得的最大价值。从第一个物品开始遍历,对于每一个物品,我们都有两种情况,选还是不选。如果选,那么f[i][j]=f[i-1][j-v[i]]+w[i],这里的意思是如果你选了第i个物品,那么它所获得的最大价值就相当于你在前i-1个物品中选,体积变为j-v[i]所获得的最大价值加上你选择第i个物品的价值w[i]。那么如果你没选呢,就相当于你从前i-1个物品中选,背包体积为j的所获得的最大价值。此时在进行一个max操作取两者所能获得的最大价值。但是这里是不是可能会第i个物品的体积很大,而超过你所枚举的j(也就是你的背包的最大体积),那么此时就需要判断一下就可以了。这里主要的就是一个状态的表示和状态的计算。

补充:

这里的话,我们可以优化一下,为什么呢,因为有些题目的话。数据量会很大,那么就会mle,多重背包就会mle。此时我们就进行优化一下空间。从AC代码中我们可以注意到,f[i][j]只会和f[i-1][]相关,也就是第i层只会和第i-1层相关,前面的i-2层是无关的,所以我们没有必要开f[N][N],只需要开f[2][n]就可以了。这其实也可以优化成一维数组,但是优化为一维数组的话,不好理解,用滚动数组的话还好理解一些,其实两者相差不大。

代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;
int w[N],v[N];
int f[2][N];

int main()
{
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>v[i]>>w[i];
    }
     int old=1,new1=0;
    for(int i=1;i<=n;i++)
    {
      swap(new1,old);
        for(int j=1;j<=m;j++)
        {
            f[new1][j]=f[old][j];
            if(j>=v[i])
            f[new1][j]=max(f[old][j-v[i]]+w[i],f[new1][j]);
        }
    }
    cout<<f[new1][m];
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值