算法:0-1背包

本文详细介绍了0-1背包问题,通过分析问题的最优子结构,展示了如何利用动态规划来求解。内容包括问题描述、问题分析、算法设计以及具体的代码实现,最后进行了总结,强调了0-1背包问题的关键在于状态转移和选择策略。
摘要由CSDN通过智能技术生成

问题描述

在这里插入图片描述

问题分析

该问题能否用动态规划来解决,先来看一下是否具有最优子结构(后免得最优解能否用到前面的最优解答案):

  • 物品种类:n (假设每种物品只有一个)
  • 购物车可容纳重量:W
  • 每个物品重量:w[i]
  • 每个物品价值:v[i]

①将购物车分成两部分:可使用容量(Wa)和未使用容量(Wb)
②逐步增加(+1)Wa,直到达到Wa=购物车总容量:W(Wb=0)
③逐步增加物品的种类w[i] ,判断Wa当中是否有剩余容量放入该物品,(这里是体现最优子结构的地方,也是最难理解的地方)
在这里插入图片描述

i表示行数,代表物品种类数
j表示列数,代表购物车可用容量
c[i][j]表示在容量为j,物品数为i的情况下,当前能装入的最大价值是多少

距离来说明这两种情况:
c[i][j]=c[i-1][j] ,j<w[i]:这个的意思是,Wa=2,目前已经放入w[0]=1,v[i]=1的物品,现在还有一个w[1]=5,v[i]=5的物品,但是放不进,所以c[i][j]=c[i-1][j]=1。

下面这种情况就要做一个比较判断,当前容量可以塞进一个新物品,但是塞进这个物品可能会拿出其他的物品,所以要判断拿上这个物品总价值高,还是不拿高。
举例说明:
当前容量为2,
已装入重量为w[0]=1,价值为v[0]=2的物品,c[1][1]=2,

注意c[1][2]=2,因为只有这一种物品,而且只有一个

此时有新物品可以选择,他的重量为w[1]=2:
如果v[1]=1,那么我们应该只装入w[0]=1的物品,这样价值是最大的,即c[2][2]=c[1][2]=2;
如果v[1]=5,那么就可以毫不留情的抛弃掉w[0],直接装入w[1],即c[2][2]=c[i-1][j-w[i]]+v[i]=c[1][0]+5=5

注意初始化的时候要多加一行一列,并且赋值为0:c[0][j]=0:没有物品,所以总价值为0,c[i][0]=0:没有容量,所以总价值为0

算法设计

在这里插入图片描述

代码

int knapsack(int W, int N, vector<int>& wt, vector<int>& val) {
    // vector 全填入 0,base case 已初始化
    vector<vector<int>> dp(N + 1, vector<int>(W + 1, 0));
    for (int i = 1; i <= N; i++) {
        for (int w = 1; w <= W; w++) {
            if (w - wt[i-1] < 0) {
                // 当前背包容量装不下,只能选择不装入背包
                dp[i][w] = dp[i - 1][w];
            } else {
                // 装入或者不装入背包,择优
                dp[i][w] = max(dp[i - 1][w - wt[i-1]] + val[i-1], 
                               dp[i - 1][w]);
            }
        }
    }

    return dp[N][W];
}

总结

0-1背包问题,无非就是状态转移+如何选择的问题,只要能找到递推公式,就比较好办了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值