清北学堂—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 魔力石 题目描述 题目描述 小 ...
随机推荐
- IO博客专栏
1. IO概览 2. 字符流与字节流的区别
- swagger基本使用指南
Maven依赖 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-s ...
- Leetcode 题目整理-8 Count and Say
38. Count and Say The count-and-say sequence is the sequence of integers beginning as follows: 1, 11 ...
- Android小记(整理一下自己犯过的错误)
时间:2019/12/20 如题,写这篇博客的原因主要是为了记录自己在Android编程中犯的一些低级的错误,以此警戒自己不要出现类似的错误. 1.在监听按钮的点击事件时,如果使用的是实现View.O ...
- 在华为云上开启FTP服务并建立FTP站点来从本地向服务器发送和下载文件
时间:2019/12/8 最近学习计算机网络的时候老师布置了一个实践作业,具体要求是两个人一组,一个在电脑上建立FTP站点,另一个开启FTP服务器来进行文件的上传和下载. 看到这个的时候我灵机一动,正 ...
- CUDA学习(七)之使用CUDA内置API计时
问题:对于使用GPU计算时,都想知道kernel函数运行所耗费的时间,使用CUDA内置的API可以方便准确的获得kernel运行时间. 在CPU上,可以使用clock()函数和GetTickCount ...
- python安装BeautifulSoup4
今天学习使用python爬虫,书上说让安装一个BeautifulSoup的插件,网上找了,说是下载压缩文件,直接解压然后,通过两行代码就实现了,我下载了两个,还是无法使用,后来就使用在在Pycharm ...
- 带大家用40行python代码实现一个疫情地图
最近两个月,因为新冠病毒无情的肆虐,相信会给每个中国人的记忆中画上重重的一笔.到今天为止,疫情形势依然十分严峻,虽然除湖北外的其他省份已经连续十一天确诊人数下降,但是接下来还有将近至少1.6亿的人口迁 ...
- 行人重识别和车辆重识别(ReID)中的评测指标——mAP和Rank-k
1.mAP mAP的全称是mean Average Precision,意为平均精度均值(如果按照原来的顺利翻译就是平均均值精度).这个指标是多目标检测和多标签图像分类中长常用的评测指标,因为这类任务 ...
- 一台电脑上配置多个git的ssh key
前几天公司的代码库全部迁移到了阿里云上,在配置git的ssh key的时候遇到了一个问题,那就是自己的密钥在添加时提示已经存在,原来是自己的个人账号上已经添加过这个密钥了,公司分配的账号就不能再添加这 ...