动态规划之矩阵连乘问题

动态规划法思想:将求解问题分解成若干个子问题,这些子问题往往是不相互独立的。

然后从这些子问题的解得到原问题的解。

动态规划法的步骤:(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;
}




  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒悟wjn

打赏可获取源码

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值