动态规划过程是:每次决策依赖于当前状态,又随即引发状态的转移。一个决策序列就是在变化的状态中产生出来的,因此,这种多阶段最优化决策解决问题的过程就称为动态规划。html
基本思想与分治法相似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各类可能的局部解,经过决策保留那些有可能达到最优的局部解,丢弃其余局部解。依次解决各子问题,最后一个子问题就是初始问题的解。java
因为动态规划解决的问题多数有重叠子问题这个特色,为减小重复计算,对每个子问题只解一次,将其不一样阶段的不一样状态保存在一个合适的数据结构中,常见的有一维数组和二维数组。算法
与分治法最大的差异是:适合于用动态规划法求解的问题,经分解后获得的子问题每每不是互相独立的(即下一个子阶段的求解是创建在上一个子阶段的解的基础上,进行进一步的求解)。数组
能采用动态规划求解的问题的通常要具备3个性质:数据结构
动态规划所处理的问题是一个多阶段决策问题,通常由初始状态开始,经过对中间阶段决策的选择,达到结束状态。这些决策造成了一个决策序列,同时肯定了完成整个过程的一条活动路线(一般是求最优的活动路线)。如图所示。动态规划的设计都有着必定的模式,通常要经历如下几个步骤。框架
初始状态→│决策1│→│决策2│→…→│决策n│→结束状态优化
划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划分后的阶段必定要是有序的或者是可排序的,不然问题就没法求解。spa
肯定状态和状态变量:将问题发展到各个阶段时所处于的各类客观状况用不一样的状态表示出来。固然,状态的选择要知足无后效性。设计
肯定决策并写出状态转移方程:由于决策和状态转移有着自然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。因此若是肯定了决策,状态转移方程也就可写出。但事实上经常是反过来作,根据相邻两个阶段的状态之间的关系来肯定决策方法和状态转移方程。code
寻找边界条件:给出的状态转移方程是一个递推式,须要一个递推的终止条件或边界条件。
通常,只要解决问题的阶段、状态和状态转移决策肯定了,就能够写出状态转移方程(包括边界条件)。
实际应用中能够按如下几个简化的步骤进行设计:
动态规划的主要难点在于理论上的设计,也就是上面4个步骤的肯定,一旦设计完成,实现部分就会很是简单。
使用动态规划求解问题,最重要的就是肯定动态规划三要素
递推关系必须是从次小的问题开始到较大的问题之间的转化,从这个角度来讲,动态规划每每能够用递归程序来实现,不过由于递推能够充分利用前面保存的子问题的解来减小重复计算,因此对于大规模问题来讲,有递归不可比拟的优点,这也是动态规划算法的核心之处。
肯定了动态规划的这三要素,整个求解过程就能够用一个最优决策表来描述,最优决策表是一个二维表,其中行表示决策的阶段,列表示问题状态,表格须要填写的数据通常对应此问题的在某个阶段某个状态下的最优值(如最短路径,最长公共子序列,最大价值等),填表的过程就是根据递推关系,从1行1列开始,以行或者列优先的顺序,依次填写表格,最后根据整个表格的数据经过简单的取舍或者运算求得问题的最优解。
for(j=1; j<=m; j=j+1) // 第一个阶段
xn[j] = 初始值;
for(i=n-1; i>=1; i=i-1)// 其余n-1个阶段
for(j=1; j>=f(i); j=j+1)//f(i)与i有关的表达式
xi[j]=j=max(或min){g(xi-1[j1:j2]), ......, g(xi-1[jk:jk+1])};
t = g(x1[j1:j2]); // 由子问题的最优解求解整个问题的最优解的方案
print(x1[j1]);
for(i=2; i<=n-1; i=i+1)
{
t = t-xi-1[ji];
for(j=1; j>=f(i); j=j+1)
if(t=xi[ji])
break;
}
复制代码