动态规划之背包问题java语言+图解
2018-03-27 01:22
309 查看
最近碰到动态规划的01背包问题,然后我就再网上四处看帖子,对于我这样的小白白来说,觉得网上的帖子写的对于新手来说,都有些晦涩难懂,于是乎,我想着用代码和图的方式来结合说明一下,有不对的,望大家及时指正。
背景:
0/1背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成0/1背包问题求解。一定要仔细体会基本思路的得出方法,状态转移方程的意义,以及最后怎样优化的空间复杂度。
问题描述:
假设孙悟空去向观音求救,观音向孙悟空展示了五个宝物,分别为A、B、C、D、E,这五种宝物的重量分别为2吨、2吨、6吨、5吨、4吨,它们的价值分别为6法力、3法力、5法力、4法力、6法力,但是孙悟空可以拿走多个宝物,但是宝物的总重量最多为10吨。请问,孙悟空应该怎么取宝物,并在自己能够承受的重量范围之内,宝物的法力最高?
(让生活多点乐趣,跟大家画了一个精美的题目内容图解)
问题分析:
每个宝物都是独特的,都只有一份,背包有最大容量限定,然后取价值最高的最优解,这很明显就是动态规划中的一种特殊情况–背包问题。
我们可以通过简单的暴力搜索,但是如果讲到算法来说,暴力搜索的空间复杂度和时间复杂度就很糟糕了。
01背包算法–结果图解
我先直接给出结果图吧,然后我带着大家一起,从结果开始分析,我们慢慢回溯。
下面给的表格矩阵,也就是最终的结果矩阵,首先我解释一下几个变量的意思。
weight :重量
value:法力值
content:背包容量
name:宝物的名字
01背包算法–结果图解
对比着结果,我们来推一下01背包算法的转移方程:
arr[i][j]=MAX{arr[i−1][j−weight[i−1]]+value[i−1](j>=weight[i−1]),arr[i−1][j]}arr[i][j]=MAX{arr[i−1][j−weight[i−1]]+value[i−1](j>=weight[i−1]),arr[i−1][j]}
看着转移方程,你可能会有点迷茫,我自己最初也是,但是只要你们推出来结果矩阵,那么,你就懂了。
转移算法是从矩阵的从左往右,从上往下进行遍历求解的。就是两层for循环,最外层是行循环,最内层是列循环。
敲黑板!!!你可能会发现我在这里是多设置了一行和一列的数据,并初始化为0。其实就是为了计算,因为每一个数据都需要用到上一行的数据,这也就是算法的精髓,将过去算过的结果记录下来,免去下一次的计算,老实讲,想到算法的人,前辈们真的很有智慧啊。
接下里,我举例说一下公式是怎么算数据的,我想有很多初学者肯定很蒙圈,我来跟你画出来。
在上图中,我列举出来的(D宝物行,背包容量为10列)坐标的取值过程,其它的过程同此一样。大家一定要尝试着自己手写递推一下,这样才能理解深刻!
于是乎,我给大家代码:
运行结果为:
结果应该还是很明显的,能带走的物品最大法力值为15。
背景:
0/1背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成0/1背包问题求解。一定要仔细体会基本思路的得出方法,状态转移方程的意义,以及最后怎样优化的空间复杂度。
问题描述:
假设孙悟空去向观音求救,观音向孙悟空展示了五个宝物,分别为A、B、C、D、E,这五种宝物的重量分别为2吨、2吨、6吨、5吨、4吨,它们的价值分别为6法力、3法力、5法力、4法力、6法力,但是孙悟空可以拿走多个宝物,但是宝物的总重量最多为10吨。请问,孙悟空应该怎么取宝物,并在自己能够承受的重量范围之内,宝物的法力最高?
(让生活多点乐趣,跟大家画了一个精美的题目内容图解)
问题分析:
每个宝物都是独特的,都只有一份,背包有最大容量限定,然后取价值最高的最优解,这很明显就是动态规划中的一种特殊情况–背包问题。
我们可以通过简单的暴力搜索,但是如果讲到算法来说,暴力搜索的空间复杂度和时间复杂度就很糟糕了。
01背包算法–结果图解
我先直接给出结果图吧,然后我带着大家一起,从结果开始分析,我们慢慢回溯。
下面给的表格矩阵,也就是最终的结果矩阵,首先我解释一下几个变量的意思。
weight :重量
value:法力值
content:背包容量
name:宝物的名字
01背包算法–结果图解
对比着结果,我们来推一下01背包算法的转移方程:
arr[i][j]=MAX{arr[i−1][j−weight[i−1]]+value[i−1](j>=weight[i−1]),arr[i−1][j]}arr[i][j]=MAX{arr[i−1][j−weight[i−1]]+value[i−1](j>=weight[i−1]),arr[i−1][j]}
看着转移方程,你可能会有点迷茫,我自己最初也是,但是只要你们推出来结果矩阵,那么,你就懂了。
转移算法是从矩阵的从左往右,从上往下进行遍历求解的。就是两层for循环,最外层是行循环,最内层是列循环。
敲黑板!!!你可能会发现我在这里是多设置了一行和一列的数据,并初始化为0。其实就是为了计算,因为每一个数据都需要用到上一行的数据,这也就是算法的精髓,将过去算过的结果记录下来,免去下一次的计算,老实讲,想到算法的人,前辈们真的很有智慧啊。
接下里,我举例说一下公式是怎么算数据的,我想有很多初学者肯定很蒙圈,我来跟你画出来。
在上图中,我列举出来的(D宝物行,背包容量为10列)坐标的取值过程,其它的过程同此一样。大家一定要尝试着自己手写递推一下,这样才能理解深刻!
于是乎,我给大家代码:
package travelling_bag; public class Main { //分别定义宝物名称、重量、法力和背包最大容量 public static String[] name = {"A","B","C","D","E"}; public static int[] weight = {2,2,6,5,4}; public static int[] value = {6,3,5,4,6}; public static int content = 10; //定义我们的记录矩阵,需要多一列和一行,也就是上面所给表中灰色的列, //因为我们下面的操作会设计到i-1和j-1,所以我们在这里需要多定义一行和一列 public static int[][] arr = new int[name.length+1][content+1]; public static int[][] bag(int[] weight, int[] value, int content, int[][] arr){ for (int i = 1; i < arr.length; i++) { //行 for (int j = 1; j < arr[i].length; j++) { //列 if(j>=weight[i-1]){ arr[i][j] = arr[i-1][j-weight[i-1]]+value[i-1]; } if(arr[i][j]<arr[i-1][j]){ arr[i][j]=arr[i-1][j]; } } } return arr; } //就是定义看一下矩阵 public static void show(){ for (int i = 0; i < arr.length; i++) { for (int j = 0; j < arr[i].length; j++) { System.out.print(arr[i][j]+"\t"); } System.out.println(); } } public static void main(String[] args) { arr = bag(weight,value,content,arr); show(); } }
运行结果为:
0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 6 6 6 0 0 6 6 9 9 9 9 9 9 9 0 0 6 6 9 9 9 9 11 11 14 0 0 6 6 9 9 9 10 11 13 14 0 0 6 6 9 9 12 12 15 15 15
结果应该还是很明显的,能带走的物品最大法力值为15。
相关文章推荐
- 算法java实现--动态规划--0-1背包问题
- Java 动态规划求解0-1背包问题
- 《JAVA》中利用《动态规划》实现《背包》问题
- 一步一步看清动态规划----背包问题(java解)
- 背包问题-动态规划-JAVA
- 动态规划之背包问题(JAVA)
- 【算法数据结构Java实现】Java实现动态规划(背包问题)
- java--0-1背包问题--动态规划解法
- 用贪心算法实现的背包问题(java语言)
- 动态规划求解背包问题(java版本)
- java 动态规划 背包问题
- 动态规划(背包问题,最长递增子序列,硬币问题)java实现
- 动态规划之0/1背包问题-java实现
- 动态规划求解背包问题(JAVA实现)
- 动态规划排线算法问题java语言实现 在一块电路板的上、下2端分别有n个接线柱。根据电路设计,要求用导线(i,π(i))将上端接线柱与下端接线柱相连
- 学习JAVA语言过程中遇到了一些问题
- 你必须知道的261个Java语言问题
- Java语言深入-构造函数的继承问题 (转)
- 转贴:Java语言的十大问题及引申思考
- 0-1背包问题及其动态规划求解之二——王晓东的书本解法