算法学习笔记(8.1)-动态规划入门

news2024/11/14 6:41:59

目录

问题特性:

最优子结构:

代码示例:(动态规划最优子结构)

上述最小代价爬楼梯的运行过程:

代码示例:

无后效性:

解析:

具体过程图示如下:

具体的代码示例:

解析:

问题特性:

动态规划的基本是通过子问题分解来求解原问题的。但是通俗来说,子问题分解是一种通用的算法思路,在分治、动态规划、回溯中的侧重点也不同。 

  1. 分治问题:递归地将原问题划分为多个相互独立的子问题,直至最小子问题,并在回溯中合并子问题的解,最终得到原问题的解
  2. 动态规划:对问题进行递归分解,但与分治算法的主要区别是,动态规划中的子问题是相互依赖的,在分解过程中会出现许多重叠的子问题。
  3. 回溯:在尝试和回退中穷举所有的可能的解,并通过剪枝避免不必要的搜索分支。原问题的解由一系列决策步骤构成,我们可以将每个决策步骤之前的子序列看作一个子问题

实际上,动态规划常用来求解最优化问题,它不仅包含重叠子问题,还具有两大特性:最优子结构,无后效性。

最优子结构:

给定一个楼梯,你每步可以上1阶或者2阶,每一个楼梯上都贴有一个非负整数,表示你在该台阶所需要付出的代价。给定一个非负整数数组cost,其中cost[i]表示在第i个台阶需要付出的代价,cost[0]为地面(起始点)。

请计算最少需要付出多少代价才能到达顶部。

若第1,2,3阶的代价分别为1,10,1,则地面爬到第3阶的最小代价为2.

设dp[i]为爬到第i个台阶付出的代价,由于第i阶只能从i-1阶或者i-2阶走来,因此dp[i]只可能等于dp[i-1] + cost[i] 或者 dp[i-2] + cost[i]。为了尽可能减少代价,我们应该选择两者居中较小的那个:

dp[i] = min(dp[i-1],dp[i-2]) + cost[i]

这里就可以直接得出最优字结构的含义:原问题的最优解是从子问题的最优解构建而来。

但是对于爬楼梯的最优子结构,我们又该怎么理解呢,它的目标是求解方案数量,但是我们将其理解称为最大方案数量,虽然题目的含义一样,但是在这里出现了最优子结构的痕迹:第n阶方案最大数量=第n-1阶和第n-2阶最大方案数量和

根据状态转移方程,以及初始状态dp[1] = cost[1]和dp[2] = cost[2]。

代码示例:(动态规划最优子结构)

# python 代码示例
def min_cost_climbing_stairs_dp(cost) :
    n = len(cost) - 1
    if n == 1 or n == 2 :
        return cost[n]
    dp = [0] * (n + 1)
    dp[1], dp[2] = cost[1], cost[2]
    for i in range(3, n + 1) :
        dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]
    return dp[n]
// c++ 代码示例
int minCostClimbingStairsDP(vector<int> &cost)
{
    int n = cost.size() - 1 ;
    if (n == 1 || n == 2)
    {
        return cost[n] ;
    }
    vector<int> dp(n + 1) ;
    dp[1] = cost[1] ;
    dp[2] = cost[2] ;
    for (int i = 3; i <= n ; i++)
    {
        dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i] ;
    }
    return dp[n] ;
}

上述最小代价爬楼梯的运行过程:

将上述代码进行空间优化,将一维压缩至0维,空间复杂度由O(n)变为O(1)

代码示例:

# python 代码示例
def min_cost_climbing_stairs_dp_comp(cost) :
    n = len(cost) - 1
    if n == 1 or n == 2 :
        return cost[n]
    a, b = cost[1], cost[2]
    for i in range(3, n + 1) :
        a, b = b, min(a, b) + cost[i]
    return b
// c++ 代码示例
int minCostClimbingStairsDPComp(vector<int> &cost)
{
    int n = cost.size() - 1 ;
    if (n == 1 || n == 2)
    {
        return cost[n] ;
    }
    int a = cost[1], b = cost[2] ;
    for (int i = 3 ; i <= n ; i++)
    {
        int temp = b ;
        b = min(a, b) + cost[i] ;
        a = temp ;
    }
    return b ;
}

无后效性:

能够有效解决问题的重要特性之一,定义:给定一个确定的状态,它的未来发展只与当前的状态有关,而与过去经历的所有状态无关。

以爬楼梯进行相关理解,给定状态i,它会发展出状态i+1和状态i+2,分别对应跳1步和跳2步。在做出这两种选择时,无须考虑状态i之前的状态,它们对i的未来没有影响。

但是下面这种情况就不一样了:如题,给定一个共有n阶的楼梯,你每一步可以上1阶或者2阶,但是不能连续两次跳1阶,请问有多少种方案可以爬到楼顶?

如图所示:爬3阶的例子

解析:

如果上一轮跳1阶上来的,下一次跳动必须跳2阶。这就意味着,下一步的选择不能由当前状态(当前所在楼梯阶数)独立决定,还和前一个状态(上一轮的楼梯的阶数)有关。

所以原来的状态转移方程dp[i] = dp[i-1] + dp[i-2]也因此失效,为了满足约束条件,我们不能直接将dp[i-1]直接放入到dp[i]中。

为此,我们需要扩展状态定义:状态[i,j]表示处在第i阶并且上一轮跳了j阶,其中j属于{1,2}。此状态定义有效地区分了上一轮跳了1阶还是2阶,我们可以根据判断当前状态从何而来。

  1. 当上一轮跳了1阶时,上上一轮只能选择跳2阶,即dp[i,1]只能从dp[i-1,2]转移过来
  2. 当上一轮跳了2阶时,上上一轮可选择跳1阶或者跳2阶,即dp[i,2]可以从dp[i-2,1]或dp[i-2,2]转移过来。

因此,在该定义下,dp[i,j]表示状态[i,j]对应的方案数。状态转移方程为:

dp[i,1] = dp[i-1,2]

dp[i,2] = dp[i-2,1] + dp[i-2,2]

具体过程图示如下:

最终,返回dp[n,1] + dp[n,2]即可,两者之和代表爬到第n阶的方案总数:

具体的代码示例:

# python 代码示例
def climbing_stairs_constraint_dp(n) :
    if n == 1 or n == 2 :
        return 1
    dp = [ [0] * 3 for _ in range(n + 1)]
    dp[1][1], dp[1][2] = 1, 0
    dp[2][1], dp[2][2] = 0, 1
    for i in range(3, n + 1) :
        dp[i][1] = dp[i - 1][2]
        dp[i][2] = dp[i - 2][1] + dp[i - 2][2]
   return dp[n][1] + dp[n][2]
// c++ 代码示例
int climbingStairsConstraintDP(int n)
{
    if (n == 1 || n == 2)
    {
        return 1 ;
    }
    vector<vector<int>> dp(n + 1, vector<int>(3, 0)) ;
    dp[1][1] = 1 ;
    dp[1][2] = 0 ;
    dp[2][1] = 0 ;
    dp[2][2] = 1 ;
    for (int i = 3 ; i <= n ; i++)
    {
        dp[i][1] = dp[i - 1][2] ;
        dp[i][2] = dp[i - 2][1] + dp[i - 2][2] ;
    }
    return dp[n][1] + dp[n][2] ;
}

解析:

在上面的约束条件中只需要考虑一个约束对象,因此我们可以通过扩展状态定义,使得问题重新满足无后效性,

给定一个共有 i 阶的楼梯,你每步可以上 1 阶或者 2 阶。规定当爬到第 i 阶时,系统自动会在第 2i 阶上放上障碍物,之后所有轮都不允许跳到第 2i 阶上。例如,前两轮分别跳到了第 2、3 阶上,则之后就不能跳到第 4、6 阶上。请问有多少种方案可以爬到楼顶?

在这个问题中,下次跳跃依赖过去所有的状态,因为每一次跳跃都会在更高的阶梯上设置障碍,并影响未来的跳跃。对于这类问题,动态规划往往难以解决。

实际上,许多复杂的组合优化问题(例如旅行商问题)不满足无后效性。对于这类问题,我们通常会选择使用其他方法,例如启发式搜索、遗传算法、强化学习等,从而在有限时间内得到可用的局部最优解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1914989.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法的复杂度

文章目录 一、算法的效率1、复杂度的概念2、复杂度的重要性 二、时间复杂度三、空间复杂度四、大O的渐进表示发五、计算复杂度案例1、计算Func1函数的复杂度2、计算Fun2的时间复杂度3、计算Func3的时间复杂度4、计算Func4的时间复杂度5、计算strchr的时间复杂度6、计算Func5的时…

解决Invalid or unsupported by client SCRAM mechanisms(dbeaver)

在用工具&#xff08;dbeaver&#xff09;链接Opengauss数据库的时候&#xff0c;报出标题的错误。原因为驱动不正确。 驱动下载地址&#xff1a;https://opengauss.org/zh/download/ 下载完的包 &#xff0c;解压后&#xff0c;里面应该有两个jar 包,使用postgresql.jar dbe…

MT3056 交换序列

思路&#xff1a; 与题目 MT3055 交换排列 类似 代码&#xff1a; #include <bits/stdc.h> using namespace std; const int N 1e4 10; int n, fa[N], b[N], d[N]; void init(int n) {for (int i 1; i < n; i)fa[i] i; } int find(int x) {return x fa[x] ?…

WebRTC批量发送消息API接口的特性有哪些?

WebRTC批量发送消息api接口怎么样&#xff1f;接口性能怎么用&#xff1f; WebRTC技术允许浏览器和移动应用进行实时通信。通过WebRTC&#xff0c;开发者可以构建视频、语音、数据共享等应用。AokSend将重点探讨WebRTC批量发送消息API接口的特性。 WebRTC批量发送消息API接口…

Qt/QML学习-PathView

QML学习 PathView例程视频讲解代码 main.qml import QtQuick 2.15 import QtQuick.Window 2.15Window {width: 640height: 480visible: truetitle: qsTr("Hello World")color: "black"PathView {id: pathViewanchors.fill: parentmodel: ListModel {List…

[Spring] SpringBoot基本配置与快速上手

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

AJAX-个人版2.0

AJAX&#xff08;Asynchronous Javascript And Xml&#xff09; 传统请求及缺点 传统的请求都有哪些&#xff1f; 直接在浏览器地址栏上输入URL。点击超链接提交form表单使用JS代码发送请求 window.open(url)document.location.href urlwindow.location.href url… 传统请…

面试总结-基础js

一、变量提升&#xff08;函数里面先形参赋值&#xff0c;再变量提升&#xff0c;最后执行代码&#xff09; 1、概念&#xff1a;当浏览器开辟出供代码执行的栈内存后&#xff0c;代码并没有自上而下立即执行&#xff0c;而是继续做了一些事情&#xff0c;把当前作用域所有带v…

C++基础编程100题-021 OpenJudge-1.4-01 判断数正负

更多资源请关注纽扣编程微信公众号 http://noi.openjudge.cn/ch0104/01/ 描述 给定一个整数N&#xff0c;判断其正负。 输入 一个整数N(-109 < N < 109) 输出 如果N > 0, 输出positive; 如果N 0, 输出zero; 如果N < 0, 输出negative 样例输入 1样例输出…

【Linux】命令执行的判断依据:;,,||

在某些情况下&#xff0c;很多命令我想要一次输入去执行&#xff0c;而不想要分次执行时&#xff0c;该如何是好&#xff1f; 基本上有两个选择&#xff0c; 一个是通过shell脚本脚本去执行&#xff0c;一种则是通过下面的介绍来一次入多个命令。 1.cmd&#xff1a;cmd&#…

SAP EWM display message对话框长度限制

1.问题 使用标准方法/scwm/cl_rf_dynpro_srvc=>display_message显示消息文本,由于消息文本过长而被截取,影响显示效果 2.解决 通过调试跟踪当前标准方法,发现屏幕显示长度为40,最多显示4行,且iv_msg_text把每一行显示字段用空格拼接起来,故以下代码需要把显示消息…

Unity 打包的安卓APK在模拟器运行一会卡死

Unity 安卓APK模拟器运行一会卡死 如题&#xff0c;unity在模拟器上运行安卓apk挂机一会就卡死&#xff0c;在真机上没问题。因为打包时勾选了这个帧率优化选项&#xff0c;2019.2之后的功能&#xff0c;最坑的时打包时默认勾选&#xff0c;所以使用这个版本打包时&#xff0c…

如何写好品牌宣传稿提升品牌曝光?看这篇文章就够了

在这个信息爆炸的时代&#xff0c;一句精炼而富有力量的宣传语&#xff0c;足以让品牌在万千竞争者中脱颖而出。撰写一篇成功的品牌宣传稿&#xff0c;不仅是对文字艺术的驾驭&#xff0c;也是对品牌灵魂的深刻洞察与精准传达&#xff0c;更是连接品牌与消费者情感与认知的桥梁…

和鲸101计划夏令营火热进行中!北中医助阵医学数据探索

上周&#xff0c;和鲸社区 2024 夏令营已经正式开营&#xff01; 从 2021 年开始&#xff0c;和鲸社区在每年暑假期间都会为大家提供集中化、系统化的数据科学相关的技能实践和培训&#xff0c;每年都有几千名同学借此机会积累宝贵的实战经验&#xff0c;丰富个人简历作品&…

Apache功能配置:访问控制、日志分割; 部署AWStats日志分析工具

目录 保持连接 访问控制 只允许指定ip访问 拒绝指定主机其他正常访问 用户授权 日志格式 日志分割 操作步骤 使用第三方工具cronolog分割日志 AWStats日志分析 操作步骤 访问AwStats分析系统 保持连接 Apache通过设置配置文件httpd-default.conf中相关的连接保持参…

Docker安装HomeAssistant

检查Docker服务是否正常运行&#xff0c;确保Docker正常运行。 systemctl status docker#输出---------------------- docker.service - Docker Application Container EngineLoaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)Activ…

mount卡住(失败)解决方案

mount -a卡主 第一步确保两边都打开了NFS服务&#xff01;&#xff01;&#xff01;&#xff01; 客户端执行mount -av 查看信息是拒绝服务 查看服务端&#xff1a;showmount -e 192.168.25.168 看提示信息处理&#xff0c;关闭两端的防火钱 遇到这个错误就是服务端不让客户端…

【音频特征提取】傅里叶变换算法源码学习记录

目录 背景快速理解FFT&#xff08;快速傅里叶变换&#xff09;IFFT&#xff08;逆傅里叶变换&#xff09;STFT&#xff08;短时傅里叶变换&#xff09; 代码实现FFT源代码IFFT源代码FFT、IFFT自己实验STFT源代码STFT自己实验 总结 背景 最近用到了相关操作提取音频信号特征&am…

stm32单片机的分类与命名

一、Stm32单片机的分类 二、Stm32单片机的命名 例如&#xff1a;STM32F103C8T6

android13 设置左右分屏修改为单屏幕,应用分屏改为单屏

1.前言 android13中,系统设置变成,左边是一级菜单,右侧是二级菜单, 这样跟我们以前android7/8/9的布局是不一样的,我们需要将它修改为一级菜单,点进去才是二级菜单这种。 效果如下 2.系统设置实现分析 它这里使用的是google新出的embedding activity, 相关的知识这里…