算法分析-----动态规划
动态规划
动态规划算法与分治法类似,基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是适合用动态规划的问题,经分解的子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,以至于最后解决问题需要耗费指数时间。然而,不同子问题的数目往往只有多项式量级。在用分治法求解时,有的子问题会被重复计算很多次,如果能保存已经解决的子问题的答案,在需要时找出求得的答案,这样就可以避免大量重复的计算。从而得到多项式时间算法。为达到这个目的,可以用一个表记录所有已解决的子问题的答案。不管该子问题以后是否被用到,只要被计算过就将其结果填入表中,这就是动态规划的基本思想。
具体的算法多种多样,但是一般具有相同的填表格式。
动态规划一般用来求解最优化问题,通常按以下4个步骤设计:
(1)找出最优解的性质,并刻画其结构特征。
(2)递归的定义最优值
(3)以自底向上的方式计算出最优值。
(4)根据计算最优值时得到的信息,构造最优解。
(1)~(3)是动态规划的基本步骤,在只需要求出最优解的情形中,(4)可省去。
以具体例子说明动态规划。(矩阵连乘、最长公共子序列、最大字段和、凸多边形最优三角剖分、多边形游戏、图像压缩、电路布线、流水作业、背包问题、最优二叉搜索树)
例1 矩阵连乘问题
/****矩阵连乘
****(1)分析最优解结构:矩阵乘积AiAi+1...Aj记为A[i:j],考察A[1:n]的最优计算次序,设矩阵从k处断****开,则(A1....Ak)(Ak+1....An),按照这个次序,先计算(A1...Ak)和(Ak+1...An)然后将计算结果相乘得****到最终结果,那么在计算A[1:n]的最优次序所包含计算矩阵子链A[1:k]和A[k+1:n]的次序也是最优的。也就****是矩阵连乘问题计算次序的最优解包含着其子问题的最优解,这种性质称为最优子结构。
****(2)建立递归关系:设计动态规划第二步就是递归的定义最优值,对于矩阵乘积的最优计算次序问题设计算****A[i:j]1<=i<=j<=n,所需要的最少连乘次数为m[i][j],则原问题的最优值为m[1][n]。当i=j时,****A[i:j]=Ai,为单一矩阵无需计算,m[i][j]=0。当i<j时,若A[i:j]的最优次序在Ak和Ak+1之间断开,那么
****m[i][j] =m[i][k]+m[k+1][j]+Pi-1*Pk*Pj。k的位置只有j-i可能,因此m[i][j]可以定义为:
****当i=j时,m[i][j]=0。当i<j时,m[i][j]=min{m[i][k]+m[k+1][j]+Pi-1PkPj}。p的含义是,可以通过****写几个矩阵计算一下,其实就是其中三个矩阵的行数。
****那么在m[i][j]断开的位置k记为s[i][j],也就可以在计算出最优值m[i][j]后,递归的由s[i][j]构造出相****应的最优解
*****(3)计算最优值:动态规划一般不用递归,递归很容易造成指数级时间,而是通过将自底而上的计算结果****保存起来,后面使用的时候查询一下即可。避免大量的重复计算。
*****
*****/
/*输入参数{p0,p1,....pn},存储着矩阵的维数,因为相邻两边的矩阵维数默认相同,对于 n 个矩阵来说,只***需 n+1 个空间即可存储。输出最优值数组m,m[i][j] 是表示第 i 个矩阵和第 j 个矩阵相乘的计算次***数,还输出最优断开位置的数组s*/
void MatrixChain(int *p,int n,int m[][],int s[][])
{
for(int i=1;i<=n;i++)
m[i][i]=0; //自身相乘次数为0
for(int r=2;r<=n;r++)
for(int i=1;i<=n;i++)
{
int j=i+r-1;;
m[i][j]=m[i][i]+m[i+1][j]+p[i-1]*p[i]*p[j];//m[i][i]=0,可以省略,初始值
s[i][j]=i;
for(int k=i+1;k<j;k++)
{
int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if(t<m[i][j])
{
m[i][j]=t;
s[i][j]=k;
}
}
}
}
//测试程序
int main()
{
int p[7] = { 30, 35, 15, 5, 10, 20, 25 };
int m[50][50];
int s[50][50];
MatrixChain(p, 6, m, s);
//for (int i = 1; i < 6; i++)
cout << m[1][6] <<endl;
return 0;
}
动态规划算法的基本要素
可以适用动态规划的两个重要性质:最优子结构性质和子问题重叠性质。动态规划的变形:备忘录方法。
1.最优子结构
设计动态规划算法的第一步通常是刻画最优解的结构,当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。问题的最优子结构性质提供了该问题可用动态规划算法求解的重要线索。在动态规划算法中,利用问题的最优子结构性质,以自底向上的方式递归的从子问题的最优解逐步构造出整个问题的最优解。
2.重叠子问题
可用动态规划算法求解的问题应具备另一基本要素是子问题的重叠性质。在递归算法自顶向下解此问题时每次产生的子问题并不总是新的问题,有些字问题会被重复计算多次,动态规划算法正是利用了这种子问题的重叠性质, 对每个子问题只解一次。之后将解保存在一个表中,当需要解此子问题时,只需要常数时间查看一下结果。
3.备忘录方法
备忘录方法是动态规划的变形,与动态规划一样,备忘录方法用表格保存已解决的子问题答案,与动态规划不同的是,备忘录方法是自顶向下的。

浙公网安备 33010602011771号