动态规划之0/1背包问题
来源:互联网 发布:百度读书软件 编辑:程序博客网 时间:2024/05/20 09:06
网上介绍动态规划和背包问题的文章多不胜数,这里就不再去粘贴复制哪些概念性的东西了,直接切入主题。
先将0/1背包问题的分析简单概括一下,我从正反两个方向阐述:
场景:现在有若干个物品,每个物品有自己的重量和价值,背包有一定的容量,在背包能容纳的下的情况下随便装入物品(物品不可分割),要求获取的价值要最大化。(本文请忽略背包用"容量"来装"重量"~~,还有为了通俗,也尽量少用数学符号)
正向分析、如果前i个物品在背包容量为j时,我们获取到了最优解,达到了最大价值(定义此最大价值为V),如果再多一个物品(给这个物品一个标识:x,重量为wx),背包容量不变仍为j,问题变成了,前i+1个物品在背包容量为j时的最大价值,那么为多少呢?
对于x物品来说,它的命运只有两个:放/不放。
我们首先需要考虑一个最基本的问题,这个容量j能否放的下x物品?不然说再多都是浪费表情,如果放不下,那么很简单,我们直接不理它,此时即使多了x物品,最大价值也=V。
如果放得下,我们再来考虑放还是不放(我们要价值最大化,所以取两者间的最大值)
1>如果不放,那么很简单,我们直接不理他,此时得到一个价值V1(显然V1==V)
2>如果放,那我们就需要重新分配这个背包,此时的最大价值为:x的价值(要放x,肯定得算上它的价值噻) + 前i个物品(这些物品我们没有动,该咋的咋的)在容量为 j-wx(放入x后,背包的可分配容量只剩j-wx)时的最大价值,我们定义为V2。所以,此时最大价值=V1 > V2 ? V1 : V2
反向分析、上面的正向分析,直接假设了前i个物品在背包容量为j时的最优解V,那么我们来考虑V=啥?
我们认为i物品的重量为wi,其实和上面的分析一样,V=第i个物品的价值 + 前i-1个物品在容量为j-wi时的最大价值,等等,这个等式成立的条件是什么?
没错,前提是我们为了获取最优解,是将i物品放入背包了的,而i物品放入背包的条件又是什么?当然是容量能够容纳i,并且在能够容纳i的情况下,放i比不放i,最终的价值更大。
下面列出代码(java,随便写的测试代码,看个意思就行了,仅供参考~~)
正向:嵌套for循环方式,此方式为从最小子问题(0个物品,背包容量为0)开始到最终解(i个物品,背包容量为j)。使用二维数组保存子问题最优解
反向:递归
package com.loren;/** * Created by loren on 2017/12/16. */public class Test01BeiBao { //物品数量 static int num = 4; //每个物品的价值数组 static int value[] = {10, 40, 30, 50}; //每个物品的重量数组和value一一对应 static int weight[] = {5, 4, 6, 3}; //背包容量 static int W = 10; public static void main(String[] args) { System.out.println("for循环-结果:" + getResult(num, value, weight, W)); System.out.println("递归-结果:" + getResultDG(num - 1, W)); } /** * 获取结果(递归版) * * @param i 物品下标从0开始,表示前i个物品 * @param j * @return */ public static int getResultDG(int i, int j) { if (j == 0) { //背包容量为0时,最大价值=0 return 0; } if (i == 0) { //递归到前0个物品时,表示背包容量为j,只有第一个物体可选时的最大价值 //如果j容量能够容纳下该物品,返回该物品的价值,否则返回0 if (j >= weight[0]) { return value[0]; } else { return 0; } } //前i个物品在容量为j时的最大价值=i-1个物品在容量为j-weight[i]的最大价值+value[i] //这个结论的前提是为了达到最大价值,是将第i个物品放入背包了的,否则最大价值=i-1个物品在容量为j时的价值 //而第i个物品是否放入背包的判断条件是:背包容量允许放入此物品且放入后的价值比不放的价值高 //判断是否需要放入此物品 if (weight[i] <= j) { int a = getResultDG(i - 1, j - weight[i]) + value[i]; int b = getResultDG(i - 1, j); return a > b ? a : b; } else { return getResultDG(i - 1, j); } } /** * @param value * @param weight * @param W 背包重量 * @return */ public static int getResult(int num, int[] value, int[] weight, int W) { //初始化二维数组,用于保存i个物品在容量为j是的最大价值 int[][] tab = new int[num + 1][W + 1];//整个二维数组需要包含0个物品在容量为j时和i个物品在容量为0时的最大价值,需要 //初始化数组,0个物品在容量为j时和i个物品在容量为0时的最大价值均为0 //之所以初始化tab[0][i]和tab[i][0],是为了在计算到第一个物品时方便,便于理解 for (int i = 0; i <= W; i++) { tab[0][i] = 0; } for (int i = 0; i <= num; i++) { tab[i][0] = 0; } for (int i = 1; i <= num; i++) { //外层循环每个物品 for (int j = 1; j <= W; j++) { //内层循环当前背包容量 if (weight[i - 1] <= j) { //如果当前物品能够放进背包,有两种情况:放或者不放,当前最大价值只需要取两种情况之间的最大值即可 //放:最大价值=当前物品的价值+(i-1)个物品在(当前容量-当前容量)时的最大价值 int v1 = value[i - 1] + tab[i - 1][j - weight[i - 1]]; //不放:最大价值=(i-1)个物品在当前容量时的最大价值 int v2 = tab[i - 1][j]; //取最大值 tab[i][j] = v1 >= v2 ? v1 : v2; } else { //如果当前物品不能放进背包,那么价值就为i-1个物品(除去当前物品)在j容量时的价值 tab[i][j] = tab[i - 1][j]; } } } //输出整个二维数组 System.out.print(" "); for (int i = 0; i <= W; i++) { System.out.print("容量:" + i + " "); } System.out.println(); for (int i = 0; i < tab.length; i++) { System.out.print("物品:" + i + "value=" + (i > 0 ? value[i - 1] : 0) + ",weight=" + (i > 0 ? weight[i - 1] : 0) + (i == 0 ? " " : " ")); for (int j = 0; j < tab[0].length; j++) { System.out.print(tab[i][j] + (tab[i][j] >= 10 ? " " : " ")); } System.out.println(); } System.out.println("----------------------"); return tab[value.length][W];//返回所有物品在容量为W时的最大价值 }}
- 动态规划之0-1背包问题
- 动态规划之0-1背包问题
- 动态规划之0-1背包问题
- 动态规划 之 0-1背包问题
- 动态规划之0-1背包问题
- 动态规划之0/1背包问题
- 动态规划之0-1背包问题
- 动态规划之 0/1背包 问题
- 动态规划之0-1背包问题
- 动态规划之0-1背包问题
- 动态规划之0-1背包问题
- 动态规划之0-1背包问题
- 动态规划之0-1背包问题
- 动态规划之0-1背包问题
- 动态规划之0-1背包问题
- 动态规划之0-1 背包问题
- 动态规划之0-1背包问题
- 动态规划之0-1背包问题
- 设计一个User类,并定义类的三个构造方法,类中有三个变量有用户名、口令、记录用户个数
- 【requireJS源码学习02】data-main加载的实现
- 哈希算法
- 解决git-忽略文件,添加gitignore,处理已经track的文件
- pytorch使用(三)网络结构可视化
- 动态规划之0/1背包问题
- 设计模式之单例模式,懒汉模式与饿汉模式
- opencv——轮廓检测
- Spring DAO(1):基础 & 数据源配置
- STM32固件库
- Windows7 系统上配置caffe GPU/CPU 的深度学习框架
- 系统吞吐量、TPS(QPS)、用户并发量、性能测试概念和公式
- tensorflow.slice_input_producer
- FasterRCNN算法:RPN层的深入理解