算法题之动态规划-01背包问题

简介: 详细讲解算法题之动态规划-01背包问题

文章首发于我的个人博客,到个人博客体验更佳阅读哦

https://www.itqiankun.com/article/1564909352

文字介绍解决背包问题

假设山洞里共有a,b,c,d ,e这5件宝物(不是5种宝物),它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包, 怎么装背包,可以才能带走最多的财富。

此时只要理解了状态转换方程f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ), f[i-1,j] },就知道这道算法的答案了,这个状态转换方程是怎么来的呢?往下看

假如背包要放第i件物品,此时如果不放第i件物品,那么问题就转化为“前i-1件物品放入重量是w的背包中”,价值为f[i-1,j];
如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的重量为j-Wi的背包中”,此时能获得的最大价值就是f[i-1,j-Wi]
再加上通过放入第i件物品获得的价值Pi,此时只要比较f[i-1,j]和f[i-1,j-Wi]+Pi那个大就能获取到背包里最大的价值是多少了。

可能还是不是太懂,那么我们看图来理解,这里就使用大佬的图片了,就是下面的图片,有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,怎么获取价值最大的背包呢

20190724183559279

首先对这个图片要知道的是:

  • 明确这张表是至底向上,从左到右生成的。
  • 然后用e2单元格表示e行2列的单元格,这个单元格的意义是用来表示只有物品e时,有个承重为2的背包,那么这个背包的最大价值是0,因为e物品的重量是4,背包装不了。
  • 对于d2单元格,表示只有物品e,d时,承重为2的背包,所能装入的最大价值,仍然是0,因为物品e,d都不是这个背包能装的。
  • 同理,c2=0,b2=3,a2=6。

对于承重为8的背包,a8=15,是怎么得出的呢?根据01背包的状态转换方程,需要考察两个值,就是下面的两个

  • 一个是f[i-1,j],这种情况就是承重为8的背包里面不放a这个物品这一种情况(根据上面的状态转换方程来的),这里i就是下面的横列的值,然后j就是指竖列的值,所以此时f[i-1,j]里面的i就是a、j就是8,因为a的下一列是b,所以f[i-1,j]就是指b8,所以此时的f[i-1,j]的值就是9
  • 另一个是f[i-1,j-Wi]+Pi,这种情况就是承重为8的背包里面要放a这个物品这一种情况(根据上面的状态转换方程来的),既然要放a这个物品,那么此时的Pi的值就是6(因为a商品的价值是6),然后因为承重为8的背包里面已经确定要放a这个物品,所以此时这个背包里面最多还只能存放的重量就是6,这里i就是下面的横列的值,然后j就是指竖列的值,所以此时f[i-1,j-Wi]里面的i就是a、j就是8、Wi就是2(这个2就是a物品的重量),所以此时f[i-1,j-Wi]就是指b6,此时b6的值是9,所以f[i-1,j-Wi]+Pi=9+6=15,所以物品a应该放入称重是8的背包里面

java代码解答这个背包问题

下面的红色代码注释里面的数组里面的第一个索引都是0,这是为了避免数组的0索引问题

下面的蓝色代码注释里面的for循环目的就是为了创建 这样的一个图片20190724183559279
,然后只要创建好上面的图片,那么我们就能知道背包问题的答案了

package com.one.util;

public class Test {
    public static int getMaxValue(int[] weight, int[] value, int w, int n) {
        int[][] table = new int[n + 1][w + 1];// 创建一个二维数组,横列是物品的价值,竖列是物品的重量
        // 蓝色代码注释开始
        for (int i = 1; i <= n; i++) { //物品
            for (int j = 1; j <= w; j++) {  //背包大小
                if (weight[i] > j) {
                    //当前物品i的重量比背包容量j大,装不下,肯定就是不装
                    table[i][j] = table[i - 1][j];
                } else { //装得下,Max{装物品i, 不装物品i}
                    table[i][j] = Math.max(table[i - 1][j], table[i - 1][j - weight[i]] + value[i]);
                }
            }
        }
        // 蓝色代码注释结束
        return table[n][w];
    }

    public static void main(String[] args) {
        int n = 5, w = 10;                    //物品个数,背包容量
        // 红色代码注释开始
        int[] value = {0,6, 3, 5, 4, 6};     //各个物品的价值
        int[] weight = {0,2, 2, 6, 5, 4};    //各个物品的重量
        // 红色代码注释结束
        System.out.println(getMaxValue(weight, value, w, n));
    }
}

原文链接

大佬链接
https://www.itqiankun.com/article/1564909352

目录
相关文章
|
27天前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
17天前
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
46 2
动态规划算法学习三:0-1背包问题
|
17天前
|
算法
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
这篇文章介绍了动态规划算法中解决最大上升子序列问题(LIS)的方法,包括问题的描述、动态规划的步骤、状态表示、递推方程、计算最优值以及优化方法,如非动态规划的二分法。
51 0
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
|
18天前
|
算法
动态规划算法学习二:最长公共子序列
这篇文章介绍了如何使用动态规划算法解决最长公共子序列(LCS)问题,包括问题描述、最优子结构性质、状态表示、状态递归方程、计算最优值的方法,以及具体的代码实现。
71 0
动态规划算法学习二:最长公共子序列
|
24天前
|
存储 算法
算法之背包问题
本文讨论了可分背包问题和0-1背包问题的区别及解决方法,其中可分背包问题可以使用贪心算法解决,而0-1背包问题则通常采用动态规划方法来找到最大价值的解决方案。
40 0
算法之背包问题
|
18天前
|
存储 算法
动态规划算法学习一:DP的重要知识点、矩阵连乘算法
这篇文章是关于动态规划算法中矩阵连乘问题的详解,包括问题描述、最优子结构、重叠子问题、递归方法、备忘录方法和动态规划算法设计的步骤。
70 0
|
27天前
|
算法 C++
【算法解题思想】动态规划+深度优先搜索(C/C++)
【算法解题思想】动态规划+深度优先搜索(C/C++)
|
27天前
|
算法 C++
【算法】DP背包问题(C/C++)
【算法】DP背包问题(C/C++)
|
8天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
5天前
|
人工智能 算法 数据安全/隐私保护
基于遗传优化的SVD水印嵌入提取算法matlab仿真
该算法基于遗传优化的SVD水印嵌入与提取技术,通过遗传算法优化水印嵌入参数,提高水印的鲁棒性和隐蔽性。在MATLAB2022a环境下测试,展示了优化前后的性能对比及不同干扰下的水印提取效果。核心程序实现了SVD分解、遗传算法流程及其参数优化,有效提升了水印技术的应用价值。