900 likes | 1.05k Views
动态规划思想. 北京大学信息科学技术学院 陈峰宏 1001213658. 纲要. 动态规划概念 动态规划思路 —— 顺推和逆推 状态压缩的动态规划 树型动态规划 动态规划优化 四边形不等式剪枝 队列优化 *凸单调性优化. 动态规划概念 —— 多阶段决策问题. B1 3 C1 1 D1 2 1 3 4 2 A1 C2 E1 2 1 2 3 B2 5 C3 1 D2. 阶段 状态 决策 转移方程 边界条件. 问题:求从 A1 到 E1 的最短路径长度。. f( i )=min{f(j)+g( i , j)} ,
E N D
动态规划思想 北京大学信息科学技术学院 陈峰宏 1001213658
纲要 • 动态规划概念 • 动态规划思路——顺推和逆推 • 状态压缩的动态规划 • 树型动态规划 • 动态规划优化 • 四边形不等式剪枝 • 队列优化 • *凸单调性优化
动态规划概念——多阶段决策问题 B13C11D1 21 342 A1C2E1 212 3 B25C31D2 • 阶段 • 状态 • 决策 • 转移方程 • 边界条件 问题:求从A1到E1的最短路径长度。 f(i)=min{f(j)+g(i, j)}, f(i)表示到从起点到节点i的最短路径长度 阶段 状态 A B C DE 思考:如果定义“路径长度”为实际长度模3的余数,为了求A1到E1的最短“路径长度”,还能用上述方法吗? f(A1)=0
动态规划算法的适用范围 • 最优子结构 • 最优决策序列的字序列也是最优的 • 无后效性 • 决策只取决于当前状态的特征因素,而和到达此状态的方式无关
递推——将最优性变成统计的动态规划 • 递推同样需要状态的划分和无后效性 • 但是递推的转移函数(状态转移方程)通常不包括max和min,而是一些统计函数——如求和 • 递推的难点通常在状态建模和转移函数的确定 • 综上所述,将递推看成动态规划的一种形式是没问题的 • 因此,接下来的内容将不区别动态规划和递推
思路 • 核心思想——提取信息的共性,将影响到今后状态决策的信息提取出来。 • 提取的信息要尽可能精简,信息提取的思路可以从搜索开始设想 • 寻找一个合适的顺序去求得每个状态——弱化阶段的概念
一个简单例子——排队(2008年北京网络预赛题)一个简单例子——排队(2008年北京网络预赛题) • n个小朋友排队(每个小朋友都不一样高)。两个小朋友a和b能够互相看见当且仅当排在它们中间的小朋友比a和b都要矮。已知队伍中一共有m对小朋友可以互相看见,问有可能有多少种排队方式。 • 数据范围:n<=80,m<=10000
一个简单例子——排队(2008年北京网络预赛题)一个简单例子——排队(2008年北京网络预赛题) • 思路方式——怎么提取信息的共性(无从下手) • 创造一种方式——从下一步做起 • 提取共性——信息的冗余,去除冗余信息后,原来的若干搜索状态合并为一个
一个简单例子——排队(2008年北京网络预赛题)一个简单例子——排队(2008年北京网络预赛题) • 是否存在更好的方法? • 换一种顺序思考
提取信息的共性 • 从上面的分析可以看出,动态规划可以看成是对搜索的一种记忆化优化 • 动态规划需要尽量使得搜索的状态保存的信息尽可能的精简——说白了就是搜索的总状态数越少越好。这一点和搜索是相同的 • 和搜索不同的是,动态规划会需要按照某种特定的顺序
寻找合适的顺序 • 这里讲的顺序分为两种,第一种是按照什么样的顺序求出每个状态的值,第二种是按照什么样的顺序来进行状态转移——或者说,状态转移方程的写法
倒推——最长不降子序列 • 寻找求得当前状态f[i]的方法 • F[0]=0; • For (i=1;i<=n;i++) • { • for (j=0;j<i;j++) • if (a[j]<=a[i]&&f[j]+1>f[i]) f[i]=f[j]+1; • }
顺推——最长不降子序列 • 根据当前状态f[i],寻找能够更新的状态 • For (i=1;i<=n;i++) f[i]=1; • For (i=1;i<n;i++) • { • for (j=i+1;i<=n;j++) • if (f[i]+1>f[j]&&a[i]<=a[j]) f[j]=f[i]+1; • }
顺推思想的应用 • 由于习惯性,几乎所有的动态规划书上都使用了倒推形式的状态转移方程。这导致 • 大多数动态规划顺推、倒推思想都能用——但是,在很多时候,使用顺推思路会方便很多。 • 顺推思路的一个基本应用——dijstra
游泳——09年合肥赛区试题 • 给定一个N×M(1<=N<=100,1<=M<=10000)的矩阵,表示一个游泳池,矩阵的每个单元可以有变速器或者钱(只能有一种),Facer经过一个单元,如果该单元有钱,facer就会得到这些钱;如果该单元有变速器,那么Facer的速度就会受到变速器的影响。钱的数额有可能是负数,变速器可能增加、也可能减少Facer的速度。Facer从矩阵的左上角的格子出发,目标是要到右上角去。Facer的行动规则如下: • Facer有两个方向的速度,水平速度和垂直速度。水平速度恒定为1。即Facer每次必然向右水平移动一格的距离。若Facer的垂直速度是v,那么,且他当前位于矩阵第x行第y列(我们不妨用<x,y>来表示),那么下一秒Facer将到达<x+v,y+1>。垂直速度会因变速器而改变。因水平速度永远不变,因此以后提到“速度”都指的是垂直速度。
游泳——09年合肥赛区试题 • Facer每到一个格子都可以设法改变自己的的速度v,将其+1,-1,也可以不改变。如果一个格子内有变速器,那么速度v也会发生改变,改变量等于该变速器的加速值(加速值可正可负)。因此,假如Facer当前速度为v,他所在的格子<x,y>中变速器的加速值为k,那么下一秒钟,Facer可能位于<x+v+k-1,y+1>,<x+v+k,y+1>或者<x+v+k+1,y+1>。 • 要注意,泳池的深度为N。即如果Facer碰到了池底,那么算作Facer在池底。如果Facer浮出水面,则算作Facer恰好在水面。也就是说,若计算得出,Facer当前的位置应为<x,y>。若x>N,则Facer实际上会位于<N,y>;同理,若x<1,则Facer位于<1,y>。 • Facer的速度v会维持,除非Facer自己改变或者碰到变速器。但还有一个例外,无论Facer当前的速度v是多少,如果Facer位于水面(第一行),则因为水面张力,Facer的速度v会瞬间变成0。 • Facer不能长时间憋气,他需要每K秒浮出一下水面。也就是说,Facer不能连续K秒使得自己的位置<x,y>中的x不为1。 • 你需要找出一种方法使得Facer能够到达右上角<1,M>,在此前提下Facer得到的钱越多越好(可能是负数)。输出最多的钱数。
解题思路 • 本题的考察点是两个 • 时间复杂度的分析 • 算法的灵活运用,关键是提取信息的共性 • 要善于利用顺推思维
传统思维 • 以每一列为阶段 • 需要保存的信息有 • 当前的行、列 • 当前的速度 • 当前是第几秒钟没有呼吸了 • 状态转移——顺推型?逆推型?
新的思维 • 分析时间复杂度——发现问题 • 信息共性——重新提取 • 换一种模型,不保存呼吸、行、速度等信息 • 新的算法——动态规划+搜索 • 转移思路——顺推
总结 • 有些时候不知道本状态会由哪些状态转移过来,但是知道本状态会对哪些状态产生影响。 • 这种时候就是和用顺推思路,而不是死板硬套形式化的状态转移方程的倒推思路 • 根据时间复杂度分析,合理选择模型也很重要
状态压缩的动态规划 • 前文提到过了信息的提取,通常需要提取的信息不会很多,是多项式级别的……但例外总是有的 • 有些时候需要提取的某些信息不是多项式级别的,而是指数级别的——于是就有了状态压缩的动态规划 • 因此,从算法思路上考虑——状态压缩的动态规划,也只不过就是想出一种办法来表示指数级别的信息而已
多维信息表示法——多进制数 • 例如,如果想表示一个5维的信息,每一维的范围是[1,3] • 那么,可以用一个5位的三进制数来表示。写程序时,写两个三进制数和一个长度为5的一维数组之间的转换函数 • 如果是[1,2]或者[1,4],那么,可以使用位运算来进行转换
POJ1185 炮兵阵地 • 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
POJ1185 炮兵阵地 • 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 • 数据范围:1<=n<=100,1<=m<=10
解题思路 • 我们先假设用搜索来做,看看需要保存那些有用的信息 • 有用的信息——当前搜索到的行、列以及最下面的炮的摆放位置 • 调整一下结构——以行为单位,那么,有用的信息就是当前的行号、以及当前行的炮的摆放状态 • 状态转移方式——顺推无疑 • 状态转移方程——搜索完成下一行的摆放状态 • 状态的表示——二进制数表示多维
时间复杂度分析 • 每一行状态最多2的10次方约1000个,因此最多100*1000=100000 • 状态转移需要搜索下一行的状态,最多需要枚举2的10次方约1000个状态 • 100*1000*1000=100000000 • 超时?NO!!
脱出监狱——2010年杭州试题 • 给定一个N*M的迷宫,(1<=N,M<=15),Facer是一个机器人。迷宫中的每个格子(矩阵的每个元素)可能是下面几个之一: • 墙:Facer不能进入该格子 • 平地:Facer可以随意进入该格,进入后没有事情发生 • 开关:迷宫中一共有K个开关,Facer必须经过所有这K个格子至少1次,把这些开关都打开。当Facer到达第K个开关的时候,Facer就能立刻飞出迷宫。 • 能量池:Facer一开始拥有一个容量为T的电池,初始时Facer的电池是充满了电的。每到一个能量池的时候,Facer可以选择是否给你的电池“充电”。如果选择充电,则该能量池被消耗,该格子变成平地,且同时Facer的电池能量回复到满电量T。
脱出监狱——2010年杭州试题 • Facer在迷宫中每行走一步需要耗费1个单位的电量,且仅有行走会耗费电量。电池没电时如果Facer仍未完成任务则会死亡(电量恰好为0时,若Facer在能量池上,则可以立即充电不算死亡)。每一次行走能够向上下左右任意一个方向行走一格的距离。现在问,Facer是否有可能走出迷宫?如果有可能,那么Facer的电池容量T最小为多少。题目中保证开关和能量池的总数不超过15。
解题思路 • 提取需要的信息? • @#¥%@#%¥#发现连搜索都无从下手 • 在最大容量不固定的情况下,本体无从下手。于是乎只能——枚举答案 • 分析——一定需要枚举吗?换一种高效的方式是否可行?比如说,二分? • 已知电池容量的情况下,整理需要保存的信息 • 优化一下,发现一个规律——最短路猜想
解题思路 • 模型转换——转换成另外一个图模型 • 需要保存的信息 • 当前处于什么位置 • 当前有哪些能量池用过了? • 当前有哪些开关打开了? • 不超过15个布尔信息,可以使用一个二进制数来表示
时间复杂度分析 • 状态——15*2的15次方 • 状态转移——15 • 总时间复杂度15*15*2的15次方,大约1千万,可以接受
综合练习题——大萌战 • 作为一个动漫粉丝,你需要带领你的队伍参加一个叫做萌战的游戏。你的队伍有四个角色——Saber,凛,樱和伊利亚。你的目标是通过这次的萌战赚取尽可能多的KID(KID是某动漫论坛的论坛币)。萌战的规则如下:除开你的队伍之外,还有其它N支队伍也参与了萌战.每只队伍由4个角色构成。你需要和每只其它的队伍打一轮,所以你一共要打N轮比赛,每轮对阵一支不同的队伍。
综合练习题——大萌战 • 每轮萌战分为三场。每一场都是你的一个角色与对方的一个角色PK,当然同一轮里面一个角色不能上多场。也就是说,你在每一轮比赛中需要从你的四个角色中选出三个来,并安排她们的出场顺序。你可以假定你的敌人的出场人物和出场顺序是完全随机的。即你的敌人的每个角色都有同样的可能性出现在这一轮,并有同样的 可能性出现在某一场上。每一轮结束后你需要将下一轮的出场名单和出场顺序提交。
综合练习题——大萌战 • 萌战结束后,你所得KID与下面两个因素相关: 1. 你一共赢的场数,当然你最多能赢3N场,最少0场,赢得场数越多所得KID越多。 2. 你 的最大“连胜数”。如果你的一个角色在某一段时间内连胜了若干场而没有败过,那么你可以拿到额外的KID。当然连胜不一定要每轮都出场了,例如,你的 Saber在第一、第二、第四轮都赢了但是第三轮你没让她上,那么Saber就有了一个三连胜。但是若Saber第三轮上场了并且输了,那么她只有二连 胜。你所得的KID就是上面两者之和。输入数据会给你有关场次数和连胜数的两张表,你需要用来计算最后得到的KID。连胜数最多为M,超过M场连胜的话,你得到的奖励和M场连胜一样多。
综合练习题——大萌战 • 每个角色都拥有一个“萌力值”。拥有较高“萌力值”的角色总能打败较低“萌力值”的角色。如果两个角色“萌力值”一样那么双方都有50%的概率获胜。你知道所有参赛角色的“萌力值”。 • 你足够聪明,在每一轮结束后的提交名单时,总会使用最好的策略使得期望得到的KID最多。那么,请问按照期望,你能得到的KID是多少?
数据范围 • 对于所有测试数据,有 1<=N<=30,0<=M<=5。
输入样例 • 假设N=2,你的4个角色战斗力分别为15,25,35,45 • 第一支敌军战斗力为10,20,30,40 • 第二支敌军战斗力为10,20,30,40 • 连胜1场奖励100,两场奖励200 • 最终获胜场次奖励为20,40,60,80,100,120
信息提取 • 先假设使用搜索,那么肯定是搜每一场的决策了 • 每一场的决策是什么? • 本题和上述几个普通动归的明显区别在哪? • 本题是个求解的过程,上述几题都是推导的过程 • 对后面有影响的信息是哪些? • 对后面的影响是什么?——对得分的影响。 • 当前的轮数,赢了的场数,每个人当前的连胜数,以及当前最大连胜数
信息提取 • 本题不是顺推,并非用当前状态去推导后面的状态。 • 但是本题使用了顺推思想,为了求得当前状态的值,需要使用后面的某些状态的值——而后面的某些状态的值需要被先求出来 • 说白了——本题的求值顺序是倒着的(倒推),但是需要求哪些值,每个值是如何来的得从顶部开始推 • 实现方式为记忆化搜索
解题思路 • 用f[I,j,k,l]表示当前是第i轮,已经赢了j场,最大连胜为k,每个人的连胜场数用一个长度为4的M+1进制数l表示时的期望得KID数 • 目标是求得f[1,0,0,0] • 为了求出它,我们需要枚举当前的决策(派哪3个人上场),然后,会得到一个继续下去的公式。最后选择最大的一个决策即可。
思考 • 增加一个规则 • 允许你贿赂某些队伍,告诉你贿赂每支队伍所需要的钱。如果你贿赂了那支队伍,那么你将能够安排地方的出场人物和出场顺序。同样,问你期望得KID数是多少
总结 • 一种动态规划(包括状态压缩)思维方式 • 假设用搜索,寻找需要保存的信息 • 精简这些信息,发现共性 • 寻找一种顺序,求得每个状态的值(可以顺推,也可以逆推,看哪种方便)
动态规划的优化 • 动态规划的优化通常可以比较明显的分成两类 • 降低时间复杂度的优化——通常称为降维 • 不一定降低时间复杂度的优化——可以称为剪枝 • 并不是说降维一定比剪枝好,许多动态规划的剪枝空间还是很大的 • 但是剪枝通常没有固定的方法,需要的是大量经验。因此,这里着重讲动态规划的降维
动态规划的降维 • 四边形不等式 • 使用队列、栈等线性数据结构降维 • *使用较高级的数据结构降维 • *凸(凹)完全单调性@@
四边形不等式——2D/1D模型介绍 • 假设数据范围为n • 状态数为n*n • 状态转移方程复杂度为O(n) • 则称当前的模型为2D/1D的。 • 四边形不等式最常见得使用就是在2D/1D模型中
四边形不等式 • 2D/1D模型有下列常见的状态转移方程形式 • d[i,j]=min{d[i,k-1]+d[k+1,j]+w[i,j]} • 其中,若w满足不等式 • w[a,c]+w[b,d]<=w[b,c]+w[a,d](a<b<c<d) • 则称w满足四边形不等式
四边形不等式——相关定理 • 定理一——若w满足四边形不等式,则d满足四边形不等式 • 定理二——设让d[i,j]取得最小值的k(路径)为K[i,j],则有k[i,j-1]<=k[i,j]<=k[i+1,j] • w满足四边形不等式当且仅当w[i,j]+w[i+1,j+1]<=w[i+1,j]+w[i,j+1]
四边形不等式——如何降维 • 根据定理二,可以在动态规划的过程中记录路径。 • 然后,在求d[I,j]的过程中,k的枚举只需要在K[i-1,j]和K[I,j+1]之间即可。 • 也就是说,从d[I,1]到d[I,m],k总共只枚举了O(m)的量级。 • 因此整体的时间复杂度是O(n^2)
四边形不等式 • 但是,我们在实际做题过程中,一般都不会去严格推导或者证明四边形不等式 • 一般使用四边形不等式,都是根据经验(直觉)来判断 • 但是,这些判断也有一些根据 • 在这里,我只能稍微讲一些典型的四边形不等式例题,而准确的使用需要经验的积累。