01背包的三种写法

22 篇文章 0 订阅

递归写法:

思路:

  1. 递归的参数:(i, m, sum):i表示当前是物品的序号,m表示背包的体积,sum表示的是当前背包里面所容纳的物品的价值的总和。
  2. 递归的出口:当 n 件物品都已经枚举完毕后,更新答案,然后返回!
  3. 递归体:每件物品都只有两个选择,选或不选,如果不选的话,那么当前背包的价值即为从前 i - 1 件物品里面选,的最大价值。所以可以直接递归到下一个物品。如果当前物品选的话,则需要预先判断当前背包的空间是否能够容纳,若能够容纳,再将其装入背包,同时记得更新参数!

代码:

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

using namespace std;

const int N = 1e3 + 10;
int w[N], v[N];
int res;
int n, m;

void dfs (int i, int m, int sum)
{
    if (i == n+1) {
        res = max(res, sum);
        return ;
    }
    
    dfs (i+1, m, sum);
    
    if  (m >= v[i]) dfs (i + 1, m - v[i], sum + w[i]);
}

int main()
{
    cin >> n >> m;
    
    for (int i=1; i <= n; i ++) {
        cin >> v[i] >> w[i];
    }
    
    dfs (1, m, 0);
    cout << res << endl;
    return 0;
}

二维DP的写法:

思路:

  1. 集合:从前 i 种物品里面选,且容积不超过背包最大体积 j 的最大价值。f[i][j]:i ~ 物品序号, j ~ 背包剩余的体积,f[i][j] ~ 当前状态下的价值之和。
  2. 属性:最大值。
  3. 计算:从前 i 件物品里面选,那么说明前 i - 1件物品已经选好了,只需要考虑第 i 件物品选还是不选,决策选还是不选取决于的是哪种决策下,价值最大,所以说取一个max值即可!若不选第 i 个物品,则更新为:f[i][j] = f[i-1][j];反之为:f[i][j] = max(f[i-1][j], f[i-1][j-v[i]] + w[i]);

代码:

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

using namespace std;
const int N = 1e3 + 10;
int f[N][N];
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i=1; i <= n ;i ++)
    {
        int v, w;
        cin >> v >> w;
        for (int j=1; j <= m; j ++ ){
            f[i][j] = f[i-1][j];
            if (j >= v) {
                f[i][j] = max(f[i][j], f[i-1][j-v] + w);
            }
        }   
    }
    cout << f[n][m] << endl;
    return 0;
}

一维DP的写法:

思路:

  1. 集合:从前n种物品里面选,容积为m的背包的最大价值。
  2. 属性:max
  3. 计算:考虑两个问题,为什么可以二维变一维?为什么需要保证逆序?实际上这两个问题是一个关联性极其强大的问题:二维变一维,是因为每次第 i 层的f[i][j] 更新都只用到了第 i - 1层的f[i-1][…],所以说,可以省去第一维度;对于第二个问题,其实也是对于第一个问题的保证,保证能够正确地更新!何出此言?逆序可以保证第 i 层更新的时候,用的是第 i - 1层的数据,而正序更新的话,则会导致用第 i 层刚更新的数据,去更新第 i 层当前的数据。如图所示:
    在这里插入图片描述

代码:

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

using namespace std;
const int N = 1e3 + 10;
int f[N];
int main()
{
    int n, m;
    cin >> n >> m;
    
    for (int i=1; i <= n; i ++) {
        int v, w;
        cin >> v >> w;
        for (int j=m; j >= v; j --) {
            f[j] = max(f[j], f[j-v] + w);
        }
    }
    cout << f[m] << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值