动态规划算法

应用场景—0-1背包问题

背包问题:有一个背包,容量为4磅,现有物品如下

物品 重量 价格
吉他(G) 1 1500
音响(S) 4 3000
电脑(L) 3 2000

要求:

  1. 达到目标为装入的背包的总价值最大,且重量不超出

  2. 要求装入的物品不可重复

动态规划算法介绍

  1. 动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为小问题进行解决,熊二一步步获取最优解的处理算法

  2. 与分治算法类似,但不同的是动态规划子问题不相互独立

  3. 动态规划可以通过填表的方式来逐步推进,得到最优解

解决0-1背包问题

主要思想

利用动态规划来解决,每次遍历到第i个物品,根据w[i]和v[i]来确定是否需要将该物品放入背包中。即对于给定的n个物品,令:

  • w[i]:第i个商品的重量

  • val[i]:第i个商品的价值

  • C:背包容量

  • v[i][j :表示前i个物品中能够装入容量为j的背包中的最大价值

则有下列结论:

v[i][0] = v[0][j] = 0;
当w[i] > j时:v[i][j] = v[i-1][j]
当j >= w[i]时:v[i][j] = max{v[i-1][j],v[i-1][j-w[i]] + val[i]}

思路图解

背包的填表过程

  1. 物品还未装入背包,初始状态

    行,0磅,1磅……代表背包容量,哪一行表示可以放入此行及 以上行的物品,但是哪一行先方哪一行的物品

    列,代表物品在对应背包容量下各自在背包中的价格

    物品 0磅 1磅 2磅 3磅 4磅
      0 0 0 0 0
    吉他(G)        
    音响(S)        
    电脑(L)        
  2. 加入现在只有吉他此时不论背包容量有多大,只能放一把吉他

    物品 0磅 1磅 2磅 3磅 4磅
      0 0 0 0 0
    吉他(G) 1500(G) 1500(G) 1500(G) 1500(G)
    音响(S)        
    电脑(L)        
  3. 假如有吉他和音响,当背包容量同时满足多个物品时,考虑哪个物品价值更高将其放入

    物品 0磅 1磅 2磅 3磅 4磅
      0 0 0 0 0
    吉他(G) 1500(G) 1500(G) 1500(G) 1500(G)
    音响(S) 1500(G) 1500(G) 1500(G) 3000(S)
    电脑(L)        
  4. 假如由吉他,音响,电脑时,先放电脑,放完之后如果有空余空间可以放入其他物品则放入,否则不用再关心

    物品 0磅 1磅 2磅 3磅 4磅
      0 0 0 0 0
    吉他(G) 1500(G) 1500(G) 1500(G) 1500(G)
    音响(S) 1500(G) 1500(G) 1500(G) 3000(S)
    电脑(L) 1500(G) 1500(G) 2000(L) 2000(L) + 1500(G)

    则有下列结论:

    //表示填入的表的第一行和第一列置0
    v[i][0] = v[0][j] = 0;

    //当新增加商品时,若新商品大于背包容量时,则直接使用上一单元格的装入策略
    当w[i] > j时:v[i][j] = v[i-1][j]

    //当新增加商品时,其容量小于背包容量,
    //装入的策略:
       //1. v[i-1][j]上一单元格的价值
       //2. v[i-1][j-w[i]] + v[i]当前商品的 价值+剩余空间装入物品价值的最大 值
       //3. 此时比较装入商品的价值,使用价值最         大的策略
    当j >= w[i]时:v[i][j] = max{v[i-1][j],v[i-1][j-w[i]] + val[i]}

代码实现

package whyAlgorithm.dynamic;

import java.util.Arrays;

/**
* @Description TODO 动态规划解决0-1背包问题
* @Author why
* @Date 2020/12/9 21:04
* Version 1.0
**/
public class KnapsackProblem {
   public static void main(String[] args) {
       int[] w = {1,4,3};//物品重量
       int[] val = {1500,2000,3000};//物品价值
       int m = 4;//背包容量
       int n = val.length;//物品个数

       //为记录放入商品的情况,定义一个二维数组
       int[][] path = new int[n+1][m+1];

       //创建二维数组
       //v[i][j]表示前i个物品能够装入容量为j的背包中最大的价值
       int[][] v = new int[n+1][m+1];

       //初始化第一行和第一列,在本程序中可以不处理,因为默认为0
       for (int i = 0; i < v.length; i++) {
           //将第一列置为0
           v[i][0] = 0;
           //将第一行置为0
           v[0][i] = 0;
      }
       //根据前面的公式动态规划处理
       for (int i = 1; i < v.length; i++) {//不处理第一行
           for (int j = 1; j < v[0].length; j++) {//不出来第一列
               //公式
               //因为i从1开始,故原公式修改为 w[i] = w[i-1]
               if (w[i-1] > j){
                   v[i][j] = v[i-1][j];
              }else {
                   //int b = v[i-1][j-w[i-1]] + val[i-1];
                   //int max = Math.max(v[i - 1][j], b);
                   //v[i][j] = max;
                   //为了记录商品存放到背包的情况不能简单地使用上面的公式,需要使用if,else体现这个公式
                   if (v[i-1][j] < v[i-1][j-w[i-1]] + val[i-1]){
                       v[i][j] = v[i-1][j-w[i-1]] + val[i-1];
                       //记录当前情况
                       path[i][j] = 1;
                  }else {
                       v[i][j] = v[i-1][j];
                  }
              }
          }
      }
       System.out.println("分配表:");
       for (int i = 0; i < v[0].length-1; i++) {
           System.out.println(Arrays.toString(v[i]));
      }

       //输出放入的哪些商品
       //遍历path,这样输出会有误,我们要最后的放入
//       for (int i = 0; i < path.length; i++) {
//           for (int j = 0; j < path[0].length; j++) {
//               if (path[i][j] == 1){
//                   System.out.printf("第%s个商品放入到背包\n",i);
//               }
//           }
//       }

       int i = path.length - 1;//行的最大下标
       int j = path[0].length - 1;//列的最大下标

       while (i > 0 && j > 0){//从path数组的最后开始找
           if (path[i][j] == 1){
               System.out.printf("第%s个商品放入到背包\n",i);
               j -= w[i-1];
          }
           i--;
      }
  }
}

算法(Java实现)—— 动态规划算法的更多相关文章

  1. 算法java实现--动态规划--电路布线问题

    /* * dianlubuxian.java * Version 1.0.0 * Created on 2017年11月30日 * Copyright ReYo.Cn */ package reyo. ...

  2. JAVA分析html算法(JAVA网页蜘蛛算法)

    近来有些朋友在做蜘蛛算法,或者在网页上面做深度的数据挖掘.但是遇到复杂而繁琐的html页面大家都望而却步.因为很难获取到相应的数据. 最古老的办法的是尝试用正则表达式,估计那么繁琐的东西得不偿失,浪费 ...

  3. 排序算法-Java实现快速排序算法

  4. 算法 | Java 常见排序算法(纯代码)

    目录 汇总 1. 冒泡排序 2. 选择排序 3. 插入排序 4. 快速排序 5. 归并排序 6. 希尔排序 6.1 希尔-冒泡排序(慢) 6.2 希尔-插入排序(快) 7. 堆排序 8. 计数排序 9 ...

  5. (java)五大常用算法

    算法一:分治法 基本概念 1.把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并. 2.分治策略是对于一个 ...

  6. 快速排序算法 java 实现

    快速排序算法 java 实现 快速排序算法Java实现 白话经典算法系列之六 快速排序 快速搞定 各种排序算法的分析及java实现 算法概念 快速排序是C.R.A.Hoare于1962年提出的一种划分 ...

  7. ID3算法Java实现

    ID3算法java实现 1 ID3算法概述 1.1 信息熵 熵是无序性(或不确定性)的度量指标.假如事件A的全概率划分是(A1,A2,...,An),每部分发生的概率是(p1,p2,...,pn).那 ...

  8. Java数据结构和算法(五)--希尔排序和快速排序

    在前面复习了三个简单排序Java数据结构和算法(三)--三大排序--冒泡.选择.插入排序,属于算法的基础,但是效率是偏低的,所以现在 学习高级排序 插入排序存在的问题: 插入排序在逻辑把数据分为两部分 ...

  9. Java数据结构和算法(一)--栈

    栈: 英文名stack,特点是只允许访问最后插入的那个元素,也就是LIFO(后进先出) jdk中的stack源码: public class Stack<E> extends Vector ...

  10. Java数据结构和算法(六)--二叉树

    什么是树? 上面图例就是一个树,用圆代表节点,连接圆的直线代表边.树的顶端总有一个节点,通过它连接第二层的节点,然后第二层连向更下一层的节点,以此递推 ,所以树的顶端小,底部大.和现实中的树是相反的, ...

随机推荐

  1. 开始使用 java8 的日期工具类

    例如,现有的类(例如java.util.Date和SimpleDateFormatter)不是线程安全的,这会导致用户潜在的并发问题.而新的LocalDate.LocalDateTime.DateTi ...

  2. python+selenium通过加载用户配置实现免登陆

    1查看profile路径 在Chrome地址栏访问chrome://version,可以查看个人资料存储位置: 2 python代码如下: from selenium import webdriver ...

  3. NOIP2012 解题报告

    TG Day1 T3 开车旅行 1. 预处理出从每座城市两人分别会到达的两座城市. 用 set 可以轻松实现. 2. 用倍增优化 DP 令 \(f_{i,j,k}\) 表示从城市 \(j\) 出发,行 ...

  4. NOIP2020 游记

    为了防止被禁赛三年,这里说明一下,本篇游记是提前开坑的. 10.9 上午模拟赛,下午初赛改成了全天初赛. 但还是想了会儿题,写了两道水题找找信心吧,毕竟前几天挂分挺严重的. 机房还是挺乱的,甚至连自己 ...

  5. 蓝桥杯——剪邮票(2016JavaB组第10题)

    剪邮票(16JavaB10) 如[图1], 有12张连在一起的12生肖的邮票. 现在你要从中剪下5张来,要求必须是连着的. (仅仅连接一个角不算相连) 比如,[图2],[图3]中,粉红色所示部分就是合 ...

  6. [GIT]获取git最新的tag

    背景 公司前端项目在Jenkins中打包,每次打包需要将新tag回推到仓库中.但是打包失败后如果不删除tag的话下次打包就会失败,需要手动删除,所以在Jenkinsfile中就需要在打包失败时自动删除 ...

  7. Visual Studio 调试技巧之即时窗口的妙用

    在 Visual Studio 中有一个窗口叫 Immediate 窗口,中文版本应该叫即时窗口.默认会在你启动调试时在 VS 编辑器中弹出来.你也可以通过 Debug | Windows | Imm ...

  8. Windows下django项目部署 通过Apache2.4+mod_wsgi

    经过几天踩坑,记录在Windows10下通过Apache2.4部署Django项目的过程 运行环境: 先说下环境,怎么安装倒是其次的,版本很重要,我是根据mod_wsgi的版本要求下载的各个版本(py ...

  9. Kafak探究之路- 内部结构小结

    1.框架与工作流 2 内部结构 kafka的每个主题分区的数据在 first-0(主题名-分区号)文件夹下,保存 n组xxx.log文件与xxx.index文件.log文件存发送消息的元数据,每个大小 ...

  10. 通过Dbeaver创建表格的时候,设置主键

    通过Dbeaver创建表格的时候,设置主键 Dbeaver介绍: ​ 这是一个开源的数据库连接工具,你需要安装jre才可以使用这个软件 在使用Dbeaver创建表的时候,会发现,不能直观地设置主键 这 ...