算法:0-1背包

文章目录

  • 问题描述
  • 问题分析
  • 算法设计
  • 代码
  • 总结

问题描述

算法:0-1背包_第1张图片

问题分析

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

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

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

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

距离来说明这两种情况:
c[i][j]=c[i-1][j] ,j

下面这种情况就要做一个比较判断,当前容量可以塞进一个新物品,但是塞进这个物品可能会拿出其他的物品,所以要判断拿上这个物品总价值高,还是不拿高。
举例说明:
当前容量为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

算法设计

算法:0-1背包_第3张图片

代码

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背包问题,无非就是状态转移+如何选择的问题,只要能找到递推公式,就比较好办了。

你可能感兴趣的:(算法)