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.优缺点分析
优点:

  1. 普适性极强,所有满足最优子结构的问题都可以用记忆化搜索解决,不必要按阶段顺序求解,甚至不必要划分阶段
  2. 有的题目中一些小规模的子问题不会对最终答案有贡献,记忆化搜索不会对这些问题求解
  3. 思路直接,是正常的分析问题解决问题思路,不需要太多推导

缺点:

  1. 在函数调用时需要消耗一定时间,而且递归层数过多可能造成栈空间超限
  2. 代码实现上稍微复杂一些(代码量大些)
  3. 程序结构复杂,不利于优化

三、递推式动态规划

一道例题配合食用:
题目描述:
给一个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时会有以下两种分法:

  1. 3×12=36
  2. 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(动态规划初步(一))的更多相关文章

  1. 清北学堂—2020.1提高储备营—Day 3(图论初步(二))

    qbxt Day 3 --2020.1.19 济南 主讲:李奥 目录一览 1.图论(kruskal算法,最短路径算法,拓扑排序) 总知识点:图论 一.kruskal算法 1.目的:求图的最小生成树 2 ...

  2. 清北学堂—2020.1提高储备营—Day 3(图论初步(一))

    qbxt Day 3 --2020.1.19 济南 主讲:李奥 目录一览 1.图论(图.图的存储方式.最小生成树的定义) 总知识点:图论 前言:众所周知,图论是一个非常重要的部分,而这次集训也可以算从 ...

  3. 清北学堂—2020.1提高储备营—Day 2 afternoon(线段树、树状数组)

    qbxt Day 2 afternoon --2020.1.18 济南 主讲:李佳实 目录一览 1.线段树 2.二叉搜索树(略过) 3.树状数组 总知识点:基础数据结构(本人初学感觉好难) 一.线段树 ...

  4. 清北学堂—2020.1提高储备营—Day 1 afternoon(二分、分治、贪心)

    qbxt Day 1 afternoon --2020.1.17 济南 主讲:李佳实 目录一览 1.二分法 2.分治 3.贪心 总知识点:基础算法 一.二分法 (1)算法分析:二分法是一种暴力枚举的优 ...

  5. 清北学堂—2020.1提高储备营—Day 4 morning(数论)

    qbxt Day 4 morning --2020.1.20 济南 主讲:李奥 目录一览 1.一些符号与基本知识 2.拓展欧几里得,逆元与欧拉定理 3.线性筛法与积性函数(非重点) 总知识点:数论 一 ...

  6. 清北学堂—2020.1提高储备营—Day 1 morning(模拟、枚举、搜索)

    qbxt Day 1 morning --2020.1.17 济南 主讲:李佳实 目录一览 1.模拟和枚举 2.基础搜索算法(DFS.BFS.记忆化搜索)以及进阶搜索算法(纯靠自学) 总知识点:基础算 ...

  7. 清北学堂—2020.1提高储备营—Day 2 morning(并查集、堆)

    qbxt Day 2 morning --2020.1.18 济南 主讲:李佳实 目录一览 1.并查集 2.堆 总知识点:基础数据结构 一.并查集 1.描述:并查集是一类十分常用的数据类型,它有着十分 ...

  8. 清北学堂—2020.3NOIP数学精讲营—Day 1 morning 重点笔记

    qbxt Day 1 morning 重点笔记 --2020.3.8 济南 主讲:钟皓曦 1 正数%负数==正数 负数%正数==负数 负数%负数==负数 a%b的答案的符号取决于a的符号. 2 快速幂 ...

  9. 清北学堂 2020 国庆J2考前综合强化 Day7

    目录 1. 题目 T1 魔力石 题目描述 Sol T2 和 题目描述 Sol T3 数对 题目描述 Sol T4 海豹王国 题目描述 Sol 考场策略 1. 题目 T1 魔力石 题目描述 题目描述 小 ...

随机推荐

  1. SVN : 在SVN检测下来的Maven项目没有Maven标志

    在Ecplise使用import->从SVN检出项目, 检出的项目没有了 Maven标志 解决方案 右键点击项目->configure->Convert to Maven Proje ...

  2. gRPC in ASP.NET Core 3.x -- Protocol Buffer(2)Go语言的例子(下)

    第一篇文章(大约半年前写的):https://www.cnblogs.com/cgzl/p/11246324.html gRPC in ASP.NET Core 3.x -- Protocol Buf ...

  3. Windows 7中的“帮助和支持”无法打开怎么办?

    win7 X64 将下面的代码导入注册表 Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\.xml] @="xmlfile&q ...

  4. session的属性设置

    2.       session的属性设置 先看案例: 登陆页面: <%@page contentType="text/html;charset=gb2312"%> & ...

  5. NJUPT_Wrj 个人训练实录

    9暑假了,开个训练实录,记录自己每天的训练以及补题(仅含个人训练,组队训练另开坑)希望能坚持下去QAQ 7.5日常:BZOJ1607线性筛.1601MST.1602LCA.1606背包.1625背包比 ...

  6. Codeforces 977B Two-gram(stl之string掉进坑)

    Two-gram is an ordered pair (i.e. string of length two) of capital Latin letters. For example, " ...

  7. 《Python学习手册 第五版》 -第4章 介绍Python对象类型

    本章的内容主要是介绍了Python的核心对象类型,后续的5.6.7.8.9章针对这些核心类型分别展开详细的说明 本章我认为重要的有几点 1.作者有谈到Python的知识结构,这个我感觉是一个大框架,可 ...

  8. (七)mybatis批量操作,分页插件

    首先使用方式很简单: SqlSession sqlSession = sessionFactory.openSession(ExecutorType.BATCH); 批量操作核心:改变执行sql的方式 ...

  9. EMC NW disaster and recovery simulation 1

    终于可以模拟成功了虽然只是个实验但是很有借鉴意义. 前期的准备就不说了都懂直接上图吧 scanner -B networker_indexclone to find out the laster bo ...

  10. Python原来这么好学-1.2节: 在Linux中安装python

    这是一本教同学们彻底学通Python的高质量学习教程,认真地学习每一章节的内容,每天只需学好一节,帮助你成为一名卓越的Python程序员: 本教程面向的是零编程基础的同学,非科班人士,以及有一定编程水 ...