DP乱弹

 
动态规划

实际上求解的是一个决策序列。

在具体求解到某一步的时候,可能有多种可能状态,每种状态可能有多种决策可供选择,由于问题的本质决定,并不能判定这些决策哪个可以发展为全局最优(否则,便可用贪心法解决了),因此,要将这些中间决策全部存储起来,这就是动态规划所说的“用空间换取时间”。由于是从问题的一个端点(起点或终点)开始递推的,而问题又是无后效性的,因此每个阶段都可以作为已经递推的各阶段的完整总结,也就是说,对于已经递推出的阶段,可以看做大问题的子问题,而对于递推到的这个阶段上的各个状态而言,当前所存储的与其相关的决策序列都应该是此问题的最优决策,这就是动态规划问题所要满足的“最优子结构”性质。而整个大问题就可以看作是求解此阶段各个状态的最优策略所带来的效益与将来要递推的各个阶段所产生的效益的最优化问题。将将来要递推的各个阶段分成一个一个阶段来看,也就是每次递推一个阶段,而递推中选择策略的依据就是使得下一个阶段的各个状态在选择了本阶段的此策略后又分别达到了这个新的子问题的最优。也就是用当前的状态和当前的决策去达到将来下一个阶段个状态的最优。这样,新的阶段上的各个状态所代表的子问题的最优决策序列就应该是刚刚为其选择的决策加上刚才那个阶段做决策所依赖的那个状态本身存储的最优决策序列。这样,就完成了又一次以往各阶段的完整总结,将递推的工作又前进了一步。直到到达问题的另一个端点。

如果问题共有N个阶段,每个阶段有M个可能状态,那需要的存储空间应该是N*M。每个阶段存储着当前阶段所采取的决策,即选择了下一阶段的哪个状态,这样,带动态规划完毕,即递推完毕后,便可从头至尾地读取此N*M数组,按阶段跟踪得到此问题的最优决策序列。

 

看两个例子。

 

一个是几乎所有算法书讲到DP都要举得例子,即多段图最短路径问题。

 

起点为A,终点为D,中间必须途径B阶段和C阶段,而B和C阶段分别有多个状态,因此从A到D有多条路径选择,即多个决策序列,每个决策序列依赖于各个阶段各个状态上所可作出的策略选择,每个决策序列的效益依赖于各个子决策所带来的效益,就是结点之间边的长度,即两点间的距离。

 

可以从终点开始递推此问题,C集合中各个结点都可以到达D,然而此事并不能判断C集合中的哪个结点即哪个状态能发展成全局最优,因此要把C集合中各个结点到达D(选择C阶段的不同结点就是在C阶段的不同决策)所带来的效益存储起来,这是向前递推的条件和根据。

 

向前递推此问题,考虑B集合。由于问题的性质决定了问题只有一个终点,即D,因此在对B中的各结点进行选择时(即选择在B阶段的策略时),应对以各个结点所代表的子问题进行完整总结,以B2结点为例,不再保存B2结点通过C集合中所有结点(C1,C2,C3,...)到达D的效益,而是只选取其中使B2所代表的子问题取得最优效益的C结点,即在B2这个点上将子问题做了完整的解决,使得B阶段可以完全独立地指导以后阶段的递推(当然,本例中,B阶段之后就到了起点A了),而不再依赖于B之后的阶段(C)。这就是动态规划。动态地规划每一个递推到的阶段中各个状态所应采取的策略,对于各个状态都存储好,不要急,由于问题只有一个起点也只有一个终点,多状态多决策只在求解问题的过程中存在,因此到了递推的终点,只有一个状态,仍然按照上述方式选取倒数第二个阶段的策略,便得到了整个决策序列,即问题的最优解。

 

另一个例子是网上到处都说的DP的入门经典题,即求连续子序列最大和。

 

这个问题有一个特例,就是如果全是负数和零的话,则直接搜索最大值输出,如果有正数的话,才转化成我们要讨论的DP问题。

 

给定一个整数序列,其中数据可正可负可为零,要求其和最大的连续子序列的和。

 

此问题的阶段数就应该是序列的长度,每个阶段要做的决策只有两种:1.放弃当前数字,从下一数字从新开始子序列;2.在当前序列中加入当前数字。

 

什么时候应该采取策略1?什么时候应该采取策略2?

首先如果加入当前数会导致子序列和为负,那么就采取策略1;如果加入当前数使得子序列的和增加或者不变,即当前数字大于等于零,则采取策略2。

但是如果当前数字小于0加入当前数字使子序列和变小,但是又不会使子序列的和小于0,这种情况应采取什么决策?

 

//

 

这要根据将来要递推的阶段来做决定。

 

//

 

难道说DP就是能找到一个动态规划公式,这个动态规划公式是从小规模问题到大规模问题的一个条件递推式。有了这个递推公式

 

待续

你可能感兴趣的:(DP乱弹)