清北学堂—2020.1提高储备营—Day 4 afternoon(动态规划初步(一))
qbxt Day 4 afternoon
——2020.1.20 济南 主讲:顾霆枫
目录一览
1.动态规划初步
2.记忆化搜索
3.递推式动态规划
4.记忆话搜索与递推式动态规划的转化
5.状态转移方程
总知识点:动态规划初步
一、动态规划初步:
1.定义:动态规划(Dynamic Programming)是是运筹学的一个分支,是求解决策过程最优化的数学方法。
动态规划被用于解决多阶段最优化决策问题。它的基本思路是将待解决的问题划分成多个阶段,每个阶段可能存在多种不同的状态。如果划分阶段后的问题满足最优子结构,则可以用动态规划算法一个阶段一个阶段,一个状态一个状态地解决问题的所有子问题,继而解决原问题。
2.概念化名词定义
先来一张图,配合食用

(1)阶段:
图中的每一行就是一个阶段。
阶段的划分是人为的。但是必须满足在一个阶段的任意状态做出任何决策后,得到的新状态都属于之后的阶段。(甚至不能在原阶段停留)
不过实际问题中,有的时候阶段并不是线性的,有的时候你很难描述阶段,但是实际上阶段只是提供了一个解决问题的顺序和设计状态的思路,设计出合理高效的状态才是解决问题的关键。
即:阶段的最大作用是辅助状态设计。
(2)状态:
图中“到达某一行某一个格子”
注意:一个格子不能算一个状态,一个状态应该描述一个事件,并且包含一切会对决策产生影响的限制条件。
比如,如果我要求走每一步时不能选择跟上一步一样的方向,那么我的状态就要额外记录我上一步走了哪个方向。变成“从前一个格子向某个方向走一步到达某一行某个格子”
描述一个状态描述一个状态用了几个“某”字,这个状态就是几维的。(原问题2维,增加限制后3维)(不过这其实不太重要)
(3)子问题:
右图中“从某一行某一个格子走到最后一行的最大得分”
如果我们把原问题看成“从第一行某一个格子走到最后一行的最大得分”
那么子问题与原问题非常相似,或者说根本就是同一个问题,相同的限制条件,相同的最终目的,只是改变了问题的规模,而解决问题需要的方法,也许可以完全仿照原问题。
(4)决策:
“向左下,正下或者右下走一步”
决策是一个集合。不同的状态可能有不同的决策集合。但是同一个状态一定有相同的决策集合。
如图,不论怎么到达的(4,1),其下一步一定只能向正下或右下;不论怎么到达的(5,2),其下一步一定只能向左下、正下或右下。
(5)转移:
“子问题(1,3)进行决策向正下方走一步吼能转化为子问题(2,3)”
转移用来描述两个子问题之间的关系,A子问题对应的状态进行决策C能到转化为B子问题,称为A→B有C转移。
(6)最优解:
不能被优化的解叫最优解,一个问题的最优解不一定唯一,但是最优解的目标值唯一。(废话)
(7)★★★★★ 最优子结构:
能动态规划解决的问题必须满足——任何一个子问题的最优解,做出第一步决策之后,剩下的决策集合仍然是转移到的子问题的最优解。这一条件叫做最优子结构。
这个条件也有等价描述如——
每个子问题的解与转移到它所经历的决策互不影响。(无后效性)
二、记忆化搜索(避免重复求解)
这个知识点我们已经在Day 1 morning大略的说过了,本篇主要说思想性的部分。
Day 1 传送门
1.思想:
开一个数组记录每一个子问题的最优解,如果在对子问题求解的过程中,发现之前已经求过了该问题的最优解,则直接返回之前求过的答案!
这样分析复杂度,每个子问题只会被求解一遍,而每个子问题求解时只会进行三次(O(1))操作,总复杂度为O(nm)
2.一般步骤
(1)提炼数学模型
(2)设计状态,定义子问题
(3)写记忆化搜索
3.例题
(1)滑雪问题
题目描述:
众所周知,滑雪只能从海拔高处滑向海拔低处。告诉你一个平面区域的海拔,滑雪时每次可以向东南西北四个方向中海拔小于当前格子的格子滑一步,求最长的滑雪路线。

分析:子问题:从(x,y)出发的最长滑雪路线
那么状态显然就是滑到了(x,y),决策也有{停止,(向上),(向下),(向左),(向右)}
而优化也是显然的,如果A格子比相邻的B格子海拔高,那么B格子的最长滑雪路线增加A格子可以用来优化A的滑雪路线。
如何确定顺序?
其实只要从左到右从上到下枚举就好了,因为每个子问题只会求解一次,当枚举到已求解过的格子时自然会直接跳过。
(伪)代码:
int Solve(子问题)
{
if (子问题已求解) return 记录的结果;
枚举每一个可以转移来的子问题 Solve(这些子问题),更新当前答案;
记录答案;
return 答案;
}
//主程序中
枚举每一个子问题 Solve(该子问题);
4.优缺点分析
优点:
- 普适性极强,所有满足最优子结构的问题都可以用记忆化搜索解决,不必要按阶段顺序求解,甚至不必要划分阶段
- 有的题目中一些小规模的子问题不会对最终答案有贡献,记忆化搜索不会对这些问题求解
- 思路直接,是正常的分析问题解决问题思路,不需要太多推导
缺点:
- 在函数调用时需要消耗一定时间,而且递归层数过多可能造成栈空间超限
- 代码实现上稍微复杂一些(代码量大些)
- 程序结构复杂,不利于优化
三、递推式动态规划
一道例题配合食用:
题目描述:
给一个N行M列的表格,每个格子里有一个整数。你从第一行选一个格子进入,之后每一步只能向左下,正下或右下走,不能走到表格之外。走到最后一行时结束,你的得分为你走过的每一个格子上数字之和,要求最大化你的得分。

记忆化搜索代码:
int Solve (int x,int y) //解决子问题:到达(x,y)的最大得分
{
if (ans[x][y]!=-INF) return ans[x][y];
if (x==1) return ans[x][y]=a[x][y]; //最小规模子问题
int res=-INF; //将最大目标值预制为最小(负无穷)
if (y>1) res=max(res,Solve(x-1,y-1)+a[x][y]);
if (y<m) res=max(res,Solve(x-1,y+1)+a[x][y]);
res=max(res,Solve(x-1,y)+a[x][y]);
return ans[x][y]=res;
}
重点:
if (y>1) res=max(res,Solve(x+1,y-1)+a[x][y]);
if (y<m) res=max(res,Solve(x+1,y+1)+a[x][y]);
res=max(res,Solve(x+1,y)+a[x][y]);
思考一下,如果在调用这一次函数之前,你能确保Solve(x+1,y+1),Solve(x+1,y+1),Solve(x+1,y)已被求解过,那么这些Solve(x+1,?)的调用就完全没有意义,还不如直接用ans[x][?]。实际上我们可以依此写出一个公式
ans[i][j]=a[i][j]+max{ans[i+1][j-1],ans[i+1][j],ans[i+1][j+1]};
f[i][j]=a[i][j]+max{f[i+1][j-1],f[i+1][j],f[i+1][j+1]};
(伪)代码2.0:
将f[1~n][0~m+1]赋值为-INF
for (int j=1;j<=m;j++) f[n][j]=a[n][j]; //求解极小子问题
for (int i=n-1;i>=1;i--)
for (int j=1;j<=m;j++)
f[i][j]=a[i][j]+max(f[i+1][j-1],f[i+1][j],f[i+1][j+1]);
for (int j=1;j<=m;j++) ans=max(ans,f[1][j]);
四、记忆化搜索与递推式动规的转化
1.例题:
乘积最大
题目描述:
设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。
比如有一个数字串:312, 当N=3,K=1时会有以下两种分法:
- 3×12=36
- 31×2=62
这时,符合题目要求的结果是: 31×2=62
现在,请你设计一个程序,求得正确的答案。
我们用两种方式来求解
Part 1:
记忆化搜索
Solve(n,k)表示序列的前n位加k个乘号的最大乘积
记序列L~R位的数字组成的整数为NUM(L,R)
显然Solve(n,k)=max{Solve(i,k-1)*NUM(i+1,n)}
即记忆化搜索的时候枚举最后一个乘号的位置,转化成这个乘号之前的序列添加k-1个乘号的最大乘积的子问题。
Part 2:
递推式动归
Solve(n,k)=max{Solve(i,k-1)*NUM(i+1,n)}
你直接把Solve(n,k)用f[n][k]替代掉就好了
清北学堂—2020.1提高储备营—Day 4 afternoon(动态规划初步(一))的更多相关文章
- 清北学堂—2020.1提高储备营—Day 3(图论初步(二))
qbxt Day 3 --2020.1.19 济南 主讲:李奥 目录一览 1.图论(kruskal算法,最短路径算法,拓扑排序) 总知识点:图论 一.kruskal算法 1.目的:求图的最小生成树 2 ...
- 清北学堂—2020.1提高储备营—Day 3(图论初步(一))
qbxt Day 3 --2020.1.19 济南 主讲:李奥 目录一览 1.图论(图.图的存储方式.最小生成树的定义) 总知识点:图论 前言:众所周知,图论是一个非常重要的部分,而这次集训也可以算从 ...
- 清北学堂—2020.1提高储备营—Day 2 afternoon(线段树、树状数组)
qbxt Day 2 afternoon --2020.1.18 济南 主讲:李佳实 目录一览 1.线段树 2.二叉搜索树(略过) 3.树状数组 总知识点:基础数据结构(本人初学感觉好难) 一.线段树 ...
- 清北学堂—2020.1提高储备营—Day 1 afternoon(二分、分治、贪心)
qbxt Day 1 afternoon --2020.1.17 济南 主讲:李佳实 目录一览 1.二分法 2.分治 3.贪心 总知识点:基础算法 一.二分法 (1)算法分析:二分法是一种暴力枚举的优 ...
- 清北学堂—2020.1提高储备营—Day 4 morning(数论)
qbxt Day 4 morning --2020.1.20 济南 主讲:李奥 目录一览 1.一些符号与基本知识 2.拓展欧几里得,逆元与欧拉定理 3.线性筛法与积性函数(非重点) 总知识点:数论 一 ...
- 清北学堂—2020.1提高储备营—Day 1 morning(模拟、枚举、搜索)
qbxt Day 1 morning --2020.1.17 济南 主讲:李佳实 目录一览 1.模拟和枚举 2.基础搜索算法(DFS.BFS.记忆化搜索)以及进阶搜索算法(纯靠自学) 总知识点:基础算 ...
- 清北学堂—2020.1提高储备营—Day 2 morning(并查集、堆)
qbxt Day 2 morning --2020.1.18 济南 主讲:李佳实 目录一览 1.并查集 2.堆 总知识点:基础数据结构 一.并查集 1.描述:并查集是一类十分常用的数据类型,它有着十分 ...
- 清北学堂—2020.3NOIP数学精讲营—Day 1 morning 重点笔记
qbxt Day 1 morning 重点笔记 --2020.3.8 济南 主讲:钟皓曦 1 正数%负数==正数 负数%正数==负数 负数%负数==负数 a%b的答案的符号取决于a的符号. 2 快速幂 ...
- 清北学堂 2020 国庆J2考前综合强化 Day7
目录 1. 题目 T1 魔力石 题目描述 Sol T2 和 题目描述 Sol T3 数对 题目描述 Sol T4 海豹王国 题目描述 Sol 考场策略 1. 题目 T1 魔力石 题目描述 题目描述 小 ...
随机推荐
- Git详解之安装
前言 是时候动手尝试下 Git 了,不过得先安装好它.有许多种安装方式,主要分为两种,一种是通过编译源代码来安装:另一种是使用为特定平台预编译好的安装包. 从源代码安装 若是条件允许,从源代码安装有很 ...
- openstack 架构
openstack 概念架构: openstack逻辑架构 常见的架构:
- 物流跟踪API-快递单订阅
上一篇文章我们讲解了轨迹查询的接口,通过快递鸟接口可以实现实时查询物流轨迹,这次给大家推荐订阅服务功能. 为了更好的理解订阅服务,我们来做个对比, 即时查询是主动查询物流轨迹,需要我们主动调用接口才能 ...
- 介绍Netty
介绍Netty 概述 Netty是由JBOSS提供的一个java开源框架,现为 Github上的独立项目.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务 ...
- FFMPEG学习----使用SDL播放PCM数据
参考雷神的代码: /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * Simplest Audio Play SDL2 (SDL2 play PCM) * * 本程序使用SDL2播放 ...
- Codeforces 1011C Fly(二分+模拟)
题意: 是有n个星球,1代表地球,然后输入一个m表示火箭的重量,然后输入了两组n个数,第一组表示在每个星球起飞时消耗一吨燃料的质量数,a[i]就表示每a[i]吨就要消耗1吨燃料,第二组就表示在每个星球 ...
- 【Bullet引擎】刚体类 —— btRigidBody
btRigidBody类主要用于刚体数据的计算. 在模拟刚体动画过程中,可以使用btRigidBody类获取所保存的刚体对象,进而控制刚体对象的旋转和位移.进行刚体模拟计算需要经常用到此类. API: ...
- 【Bullet引擎】Bullet物理引擎简单说明
说明 Bullet是一款开源的物理模拟计算引擎,包括刚体.柔体.弹性体等,是世界三大物理模拟引擎之一(包括Havok和PhysX),被广泛应用于游戏开发(GTA5等)和电影(2012等)制作中. Bu ...
- Java范型学习笔记
对于范型的使用或者说印象只有集合,其他地方即使使用过也不知道,反正就是只停留在List<E> Map<K, V>,最近刚好闲来无事,就找找资料学习一下:下列为个人学习总结,欢迎 ...
- css3 动画 示例
/* animation */ .a-bounce,.a-flip,.a-flash,.a-shake,.a-swing,.a-wobble,.a-ring{-webkit-animation:1s ...