动态规划法思想:将求解问题分解成若干个子问题,这些子问题往往是不相互独立的。
然后从这些子问题的解得到原问题的解。
动态规划法的步骤:(1)刻画该问题的最优解的结构特征(2)递归的定义最优值;(3)计算最优值(4)根据
计算最优值时的到的信息,构造最优解。
1.矩阵连乘问题
(1)两个矩阵相乘的算法
public static void matrixMultiply(int a[][],int b [][],int c[][],int ra,int ca,int rb,int cb) { if(ca!=rb) throw new IllegalArgumentException("矩阵不可以乘"); for(int i=0;i<ra;i++) for(int j=0;j<cb;j++){ int sum=a[i][0]*b[0][j]; for(int k=1;k<ca;k++){ sum+=a[i][k]*b[k][j]; } c[i][j]=sum; } }
(2)计算最优值
public static void matrixChain(int p[],int m[][],int s[][])//p:所有矩阵维数表示,m:最优数乘次数,s:最佳断点
{ int n=p.length-1;
for(int i=1;i<=n;i++)m[i][j]=0;//将所有本身矩阵赋值为0.
for(int r=2;r<=n;r++){//从两个矩阵的连乘开始计算
for(int i=1;i<=n-r+1;i++){//n-r+1:当前长度为r的矩阵连乘有几个
int j=i+r-1;//从当前i开始长度为r的矩阵连乘尾部是j
m[i][j]=m[i][i]+m[i+1][j]*p[i-1]*p[i]*p[j];//计算当前断点为i的矩阵的最优数乘次数
s[i][j]=i;
/*将断点放入s数组中*/
for(int k=i+1;k<j;k++){//将断点往后移动一位(i+1),求数乘次数看是否小于断点i的数乘次数,则替换原来的m[i][j],将新断点k=i+1放入s数组中。
int t=m[i][k]=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;
}
}
}
}
}
(3)动态规划算法的基本要素
1.最优子结构
当问题最优解包含其子问题的最优解时,称该问题具有最优子结构性质。
2.重叠子问题
在用递归算法自顶向下求解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。
动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其保存在一个表格中,
当再次需要解此问题时,只是简单地用常数时间查看一下结果。
//矩阵连乘递归表示(求最优数乘次数)
public static int recurMatrixChain(int i,int j)
{
if(i==j) return 0;
int u=recurMatrixChain(i+1,j)+p[i-1]*p[i]*p[j];//以i为断开点求数乘次数
s[i][j]=i;
for(int k=i+1;k<j;k++){//从i+1开始求每个阶乘次数看是否小于以i开始的。
int t=recurMatrixChain(i,k)+recurMatrixChain(k+1,j)+p[i-1]*p[k]*p[j];
if(t<u){
u=t;
s[i][j]=k;
}
}
return u;//返回当前最优值
}
3.备忘录方法
备忘录方法是动态规划算法的变形。与动态规划算法一样,备忘录方法用表格保存已解决的子问题的答案,
在下次需要解决此子问题时,只要简单的查看该子问题的解答,而不必重新计算。与动态规划算法不同的是,
备忘录方法的递归方式是自顶向下的,而动态规划算法是自底向上递归的。备忘录的区别在于为每个解决过
的子问题建立了备忘录已被需要时查看,避免了相同子问题的重复求解。
public static int memoizedmatrixChain(int n)
{
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
m[i][j]=0;//0代表子问题还没有计算过
return lookupChain(1,n);
}
private static lookupChain(int i,int j)
{
if(m[i][j]>0) return m[i][j];//>0表示有此问题的结果,直接返回就可以
if(i==j) return 0;
int u=lookupChain(i+1,j)+p[i-1]*p[i]*p[j];
s[i][j]=i;
for(int k=i+1;k<j;k++){
int t=lookupChain(i,k)+lookupChain(k+1,j)+p[k-1]*p[k]*p[j];
if(t<u)
u=t;
s[i][j]=k
}
m[i][j]=u;
return u;
}