五大常用算法之三:动态规划

2023-10-27

动态规划:

动态规划(Dynamic Programming,简称DP),需要分解出问题的子结构以及通过子结构重新构造最优解。动态规划不像回溯法,有套路可以套用,动态规划需要大量练习,才能掌握规律。

一般思路:

1.判断问题的子结构,有最优子结构时,可用动态规划!!(即从子问题的最优解,就能拼接出整体的最优解!!)

2.求解重叠子问题。一个递归算法不断地调用同一问题(子问题大量重复,可以存储,减少计算),递归可以转化为查表从而利用子问题的解。(注意与分治法区别开,分治法每次递归都产生新的问题)

特殊思路:备忘录法

备忘录法是动态规划的一种变形,最开始随机填一个数字,遇到子问题时,计算并填表。

实例可参照矩阵链乘法。

常见题目:

1. 硬币找零:假设有1,3,5三种硬币,数量无限,问当总额为某个值时需要最少硬币数为多少。

2. 装配线调度:某个工厂有两条装配线,汽车底盘经过每个流程时都有相应的时间消耗,问怎么安排,可以让进入流水线到出厂时,总时间最少。

3. 字符串相似度/编辑距离(edit distance)

有两个不同的字符串,只对一个字符串进行“增删改”操作,每次变化只有一个字符,问变成另一个字符串时,最少操作几次?

4.最长公共子序列(Longest Common Subsequence,LCS)

对于序列S和T,求它们的最长公共子序列。例如X={A,B,C,B,D,A,B},Y={B,D,C,A,B,A}则它们的LCS是{B,C,B,A}和{B,D,A,B}。求出一个即可。

5.铺瓷砖问题(剑指offer,编程之美原题)

用 1 * 2 的瓷砖覆盖 n * m 的地板,问共有多少种覆盖方式?

答:可以转换为斐波那契数列题。f(n)=f(n-1)+f(n-2);

6.  0-1背包

题目背景如下:有一个背包,容量有限。还有好几样物品,体积和价值各不相同,如何尽量装最高价值的物品呢?用实际数据举例如下:

* 物品编号: 1 2 3 4
* 物品体积: 2 3 4 5
* 物品价值: 3 4 5 6

即前i件物品,容积为j时,最大价值为dp[i][j],用图表法计算如下:

有3种可能。

总容量连当前物品都放不下,那么当前物品肯定不放。前i个物品总体组合与前i-1一致。那么就把问题抛给前i-1了

总容量可以放下当前这一个物品。那么,给当前物品留有相应空间下,剩下的空间内,前i-1个物品总价值加当前的物品价值的组合。

总容量放得下当前物品,但还有一种可能性,我不放当前的,那么照顾当前的物品,还不如之前的i-1个物品呢。

实际举例如下:

第一种情况。如dp[3][3],当前物品体积是4,但是总容量只有3,根本放不下,那么dp[3][3],只能和dp[2][3]一致,都是4.

第二种情况,放得下。如dp[3][4],此时第3个体积为4,容量为4,总容量恰好能放下当前的。如果放当前的,那么留给之前的体积仅为0,一个都不放。第3个价值为5,所以总共价值为5。

如果不放该物品,那么dp[i][j]=dp[i-1][j]=4。它俩取最大值。当然是5.所以dp[3][4]=5.

总结:

注意:当前装得下时,指的是总容量装得下!!!要不装这个最大的,把问题抛给前面。要不不装大的,直接用前面的。这个思路和青蛙跳楼梯是一样的!!!!

参考文献:https://www.cnblogs.com/jiyongjia/p/13475026.html

import java.util.ArrayList;

/**
 * Date: 2020/11/11 11:36
 * Description:
 * <p>
 * 问题:现有背包。其中有四个商品。价值体积如下
 * 物品编号: 1    2    3    4
 * 物品体积: 2    3    4    5
 * 物品价值: 3    4    5    6
 * 问:如何才能保证在背包容量为8的情况下装的价值最大?
 * <p>
 * 步骤1:填表之后的结果:
 * 0	0	0	0	0	0	0	0	0
 * 0	0	3	3	3	3	3	3	3
 * 0	0	3	4	4	7	7	7	7
 * 0	0	3	4	5	7	8	9	9
 * 0	0	3	4	5	7	8	9	10
 * 步骤2:回溯
 *
 * @author zf
 */
public class beibao {
    public static void main(String[] args) {
        int[] size = new int[]{0, 2, 3, 4, 5};   //第0位放一个默认的0值,为了下边方便取size[i]就为i号物品的体积
        int[] money = {0, 3, 4, 5, 6};    //第0位放一个默认的0值,为了下边方便取money[i]就为i号物品的价值
        int target = 8;  //指定的背包大小
        //调用
        int[][] ints = dpWrite(size, money, target);
        ArrayList<Integer> huisu = huisu(ints, size, target);
        System.out.println("您输入的背包大小是:" + target);
        System.out.println("添加的物品编号是:" + huisu);
        System.out.println("最大价值:" + ints[size.length - 1][target]);

    }

    public static int[][] dpWrite(int[] size, int[] money, int targetValue) {
        //这里构造一个例如4*8的dp,行代表截止到i背包的最优组合的价值,j代表的背包的容量值
        int[][] dp = new int[size.length][targetValue + 1];
        //初始化第0行的值
        for (int j = 0; j <= targetValue; j++) {
            dp[0][j] = 0;
        }
        //初始化第一列的值
        for (int i = 1; i < size.length; i++) {
            dp[i][0] = 0;
            //dp[i][1] = 0;
        }
        //初始化中间值i
        for (int i = 1; i < size.length; i++) {
            for (int j = 1; j <= targetValue; j++) {
                //如果第i号背包的体积小于当前的j背包容量,就保持和dp[i-1]值相同,即没放入
                if (size[i] > j) {
                    dp[i][j] = dp[i - 1][j];
                } else {
                    /*即如果当前i号物品体积可以放入的话,就看预留该体积后剩余的价值在i-1号物品中的最大值加上该物品的价值和是否
                     是大于dp[i-1][j]的值,谁大取谁*/
                    dp[i][j] = Math.max(dp[i - 1][j - size[i] > 0 ? j - size[i] : 0] + money[i], dp[i - 1][j]);
                }
            }
        }
        //这样就填表完成了。剩下的就是需要回溯取出看对应某价值target的物品组合是什么
        //先打印一下填的表
        /*for (int i = 0; i < dp.length; i++) {
            for (int j = 0; j < dp[i].length; j++) {
                System.out.print(dp[i][j]+"\t");
            }
            System.out.println();
        }*/
        return dp;
    }

    public static ArrayList<Integer> huisu(int[][] dp, int[] size, int t) {
        ArrayList<Integer> res = new ArrayList<>();
        int i = dp.length - 1;
        int j = t;
        while (i > 0 || j > 0) {
            if (dp[i][j] == dp[i - 1][j]) {
                i--;
            } else {
                res.add(i);
                j = j - size[i];
                i--;
            }
        }
        return res;
    }
}

 

 

7. 有代价的最短路径

青蛙跳台阶问题。(这个和硬币找零很像) 

8.M*N的矩阵最短路径问题

有一个M*N的矩阵,每个网格都有一个值,求起点grid[0][0]到grid[M-1][N-1]的值的最小累加和。

这个问题很简单,构造一个相同大小的矩阵dp[M-1][N-1],首先计算第一行和第一列的值,然后其余值都为dp[i][j]=grid[i][j]+Math.min(dp[i-1][j],dp[i][j-1]),最后返回dp[M-1][N-1]即可。

public static int minPathSum(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }
        int rows = grid.length,cols = grid[0].length;
        int[][] dp = new int[rows][cols];
        dp[0][0] = grid[0][0];
        //第一列的初始值
        for (int i = 1; i < rows; i++) {
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        //第一行的值
        for (int j = 1;j < cols;j++){
            dp[0][j] = grid[0][j] + dp[0][j-1];
        }
        //填写其他地方的值
        for (int i = 1;i<rows;i++){
            for (int j = 1;j<cols;j++){
                dp[i][j] = grid[i][j] + Math.min(dp[i-1][j] , dp[i][j-1]);
            }
        }
        return dp[rows -1][cols -1];
    }

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

五大常用算法之三:动态规划 的相关文章

  • 图像处理之纹理特征提取

    旋转不变性 图像旋转时 所选特征不随图像的旋转而发生变化 LBP参考 LBP纹理特征提取 灰度不变性 旋转不变性 import numpy as np from PIL import Image import math def LBP sr

随机推荐

  • chatgpt赋能python:PythonTCP断开连接原因和解决方案

    Python TCP 断开连接原因和解决方案 Python 是一种广泛使用的编程语言 它支持网络编程 数据处理 人工智能 机器学习等诸多领域 在网络编程中 Python 通常使用 TCP 连接传输数据 然而 在使用 TCP 连接传输数据的过
  • eclipse新建项目有红叉,项目可以正常启动。解决办法。

    eclipse里遇到红叉或者报错 首先应该在Window gt Show View gt Problems下查看错误信息 一般可以知道报错原因 报错有很多原因 以下是我自己遇到的 1 Project configuration is not
  • unity中fixedUpdate和Update的区别

    下面这段代码演示游戏暂停 using UnityEngine using System Collections public class GamePauseTest MonoBehaviour public float moveSpeed
  • 【框架篇】Gin框架源码解读【更新中】

    1 中间件 中间件的实现 依照设计模式中责任链模式 依次调用当前路由 注册的中间件 gin go HandlerFunc defines the handler used by gin middleware as return value
  • Perl 批量添加Copyright版权信息

    对所有输入文件 如果没有版权信息则加上版权信息 否则什么都不做 并对原文件以 bak结尾备份 开始我使用如下程序 尝试前千万先备份输入的文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2
  • 财报解读:创维集团2022年业绩表现凸显韧性,新能源业务将大有作为

    2023年3月23日 创维集团披露了2022年财报 总营收534 91亿元 同比增长5 03 归属母公司净利润8 27亿元 同比下降49 39 在电视行业正处于阵痛期的情况下 这份业绩展现了公司的发展韧性 而从财报也可以看出 创维感受到了电
  • 录音如何转文字?这几款音频转文字工具可以给到你帮助

    记录文本速度总是赶不上倾听语音速度 咋整 别急 这有一招献给你 我们可以借助音频转文字工具 快速将语音信息转写 轻松解放双手 音频转文字工具不仅转写语音的速度快 而且转写效果杠杠的 值得一试哦 话不多说 音频转文字免费教程双手奉上 有需要的
  • DS18B20温度传感器使用介绍

    DS18B20温度传感器简介 DS18B20是一种数字温度传感器 应用非常广泛 它输出的是数字信号 同时具有体积小 硬件资源耗费少 抗干扰能力强 精度高等特点 DS18B20温度传感器特点 1 采用单线接口方式 DS18B20温度传感器仅需
  • 实现按钮悬停动画

    知识点与技巧 伪元素 使用伪元素来作为按钮悬停效果动画展示的元素 z index 的使用技巧 使用z index属性来控制按钮和伪元素的层次关系 transform transition 复习 使用transform transition两
  • 舵机的使用方法和一些注意事项

    舵机是我们经常使用的一个工具 它可以说是直流电机的进化版本 只需要一根信号线就能方便的控制舵机旋转固定的角度 下面我们就来看一看舵机的使用方法和一些使用过程中的注意事项 一般的舵机总共有三条线 电源线 供电线 和信号线 其中红色的是电源正极
  • 在idea隐藏掉不想要看到的文件(设置隐藏文件)

    一 为什么隐藏 因为想 通常 我们会在项目中 看到很多不常用或者根本不操作的文件 那么 我们就会选择 隐藏 掉 注 但是需要心中有数 有些文件隐藏后 可能会影响开发 谨慎 二 如何设置 1 找到File gt Setting gt File
  • vite和esbuild/roolup的优缺点

    esbuild 优点 基于go语言 go是纯机器码 不使用 AST 优化了构建流程 多线程并行 缺点 esbuild 没有提供 AST 的操作能力 所以一些通过 AST 处理代码的 babel plugin 没有很好的方法过渡到 esbui
  • 第十天Python之面向对象(OOP)基本概念

    面向对象编程 Object Oriented Programming 简写 OOP 目标 了解 面向对象基本概念 一 面向对象基本概念 我们之前学习的编程方式就是 面向过程 的 面向过程 和 面向对象 是两种不同的 编程方式 对比 面向过程
  • Linux学习笔记--rm命令(删除文件或目录)

    rm 英文名remove 删除的意思 1 命令格式 rm 选项 文件或目录 2 常用选项 rm f 强行删除 忽略不存在的文件 不提示确认 f为force的意思 rm i 进行交互式删除 即删除时会提示确认 i为interactive的意思
  • CentOS7.x系统中使用Docker时,在存储方面需要注意的问题

    简述 1 Docker 1 12 6 v17 03文档中CentOS7系统下安装时 明确说明 用于生产时 必须使用devicemapper驱动的direct lvm模式 需要我们提前准备好块设备 以提供更好的稳定性和性能 默认使用devic
  • Java阿里云短信发送工具类

    短信服务API介绍 阿里云短信发送 调用SendSms发送短信 短信服务 阿里云帮助中心
  • 基于Hutools图片上传下载

    1 pom依赖
  • Python视觉处理(二)线检测

    python线检测使用的时cv HoughLinesP 函数 它有两个参数 minLineLength 线的最短长度 比这个线短的都会被忽略 MaxLineGap 两条线之间的最大间隔 如果小于此值 这两条线就会被看成一条线 这个函数的返回
  • 物理层(1.物理层基本概念&2.数据通信基础知识)

    物理层的作用就是在连接计算机的传输介质上传输数据比特流 并且尽可能屏蔽掉传输媒体和通信手段的差异 一 物理层的基本概念 1 机械特性 指明接口所用接线器的形状和尺寸 引线数目和排列 固定和锁定装置等 2 电气特性 指明在接口电缆的各条线上出
  • 五大常用算法之三:动态规划

    动态规划 动态规划 Dynamic Programming 简称DP 需要分解出问题的子结构以及通过子结构重新构造最优解 动态规划不像回溯法 有套路可以套用 动态规划需要大量练习 才能掌握规律 一般思路 1 判断问题的子结构 有最优子结构时