• 动态规划矩阵连乘算法(C/C++)


    算法总体思想

            动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题

    5437ca95ab2b4cebb28062458d009d12.png        但是经分解得到的子问题往往不是互相独立的。不同子问题的数目常常只有多项式量级。在用分治法求解时,有些子问题被重复计算了许多次。 1ee782ae7977483fb2e436a9320be3d9.png

            如果能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,就可以避免大量重复计算,从而得到多项式时间算法。

    5b55f77b926c42738afe6cb3e2a92a63.png

    动态规划基本步骤

    • 找出最优解的性质,并刻划其结构特征。
    • 递归地定义最优值。
    • 以自底向上的方式计算出最优值。
    • 根据计算最优值时得到的信息,构造最优解。

     矩阵连乘问题

    b53e1c804f0d409a83b7507060cacd1e.png 7e8fb756441841bb9bcdbc262876aba5.png 2fdbed9bf8424e969a288ffecfa08fab.png

     完全加括号的矩阵连乘积可递归地定义为:

    (1)单个矩阵是完全加括号的;

    (2)矩阵连乘积X是完全加括号的,则X可表示为2个完全加括号的矩阵连乘积, 即Y和Z的乘积并加括号,即X=(YZ),Y和Z也是完全加括号的。

            给定n个矩阵 {A1,A2,、、、An} ,其中Ai与 Ai+1是可乘的,i=1,2,、、、n-1。考察这n个矩阵的连乘积 A1A2、、、An。         

            由于矩阵乘法满足结合律,所以计算矩阵的连乘可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定。

            如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。

    穷举法:

            列举出所有可能的计算次序,并计算出每一种计算次序相应需要的数乘次数,从中找出一种数乘次数最少的计算次序。  

    算法复杂度分析:

            对于n个矩阵的连乘积,设其不同的计算次序为P(n)。

            由于每种加括号方式都可以分解为两个子矩阵的加括号问题:(A1...Ak)(Ak+1…An)可以得到关于P(n)的递推式如下

    3a979b57d3a148aaa01cab3d2aabf3dc.png67029da24a6b4ecbb36990a8b5e6321b.png

    穷举法:计算量非常大,这种方案不可行
    动态规划

    (1)首先分析最优解的结构

    将矩阵连乘AiAi+1、、、Aj 简记为A[i:j] ,这里i≤j考察计算A[i:j]的最优计算次序。设这个计算次序在矩阵Ak和Ak+1之间将矩阵链断开,i≤k

    (AiAi+1A、、、Ak)(Ak+1Ak+2、、、Aj)

    计算量:A[i:k]的计算量加上A[k+1:j]的计算量,再加上A[i:k]和A[k+1:j]相乘的计算量 615ee2bf2c464fa4a1574744c158628f.png

    (2)建立递归关系

            设计算A[i:j],1≤i≤j≤n,所需的最少数乘次数m[i,j],则原问题的最优值为m[1,n].

    98028957273b4f82b363d3633edbd59e.png add808b6857c49ab9910ca0f64d86372.png

    (3)以自底向上的方式求最优值

    对于1≤i≤j≤n不同的有序对(i,j)对应于不同的子问题。因此,不同子问题的个数共有:  5736f961ca444052a77ad5a608962eb1.png
    在递归计算时,许多子问题被重复计算多次。这也是该问题可用动态规划算法求解的又一显著特征
    用动态规划算法解此问题,可依据其递归式以自底向上的方式进行计算。
    在计算过程中,保存已解决的子问题答案。每个子问题只计算一次,需要时只要查一下子问题的结果,避免大量的重复计算,最终得到多项式时间的算法。
     

     用动态规划法求最优值

    1. void MatrixChain(int *p,int n,int **m,int **s){
    2. for (int i = 1; i <= n; i++) m[i][i] = 0;
    3. for (int r = 2; r <= n; r++)
    4. for (int i = 1; i <= n - r+1; i++) {
    5. int j=i+r-1;
    6. m[i][j] = m[i][i]+m[i+1][j]+ p[i-1]*p[i]*p[j];
    7. s[i][j] = i;
    8. for (int k = i+1; k < j; k++) {
    9. int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
    10. if (t < m[i][j]) { m[i][j] = t; s[i][j] = k;}
    11. }
    12. }
    13. }

    算法复杂度分析:

            算法主要计算量取决于算法中子问题的数量,已知为O(n2),求每个子问题的最优值的时间复杂性O(n)(即k控制循环次数最大值),因此算法的计算时间上界为O(n3)。算法所占用的辅助空间显然为O(n2)。

    adbd9d30ee984fbfbfe4ebdd272c5172.png 872f8ca1a6304b08b7c245aa735928c3.png

    (4)递归算法构造最优解

    1c61ffd885ef49128446dcda92a23ada.png

     参考代码

    1. #include<iostream>
    2. #define N 20
    3. using namespace std;
    4. void MatrixChain(int p[N],int n,int m[N][N],int s[N][N]){
    5. int i,j,t,k;
    6. int r;
    7. for(i=1;i<=n;i++){
    8. m[i][i]=0;
    9. }
    10. for(r=2;r<=n;r++){
    11. for(i=1;i<=n-r+1;i++){
    12. j=i+r-1;
    13. m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];
    14. s[i][j]=i;
    15. for(k=i+1;k<j;k++){
    16. t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
    17. if(t<m[i][j]){
    18. m[i][j]=t;
    19. s[i][j]=k;
    20. }
    21. }
    22. }
    23. }
    24. }
    25. void Traceback(int i,int j, int s[][N]){
    26. if(i==j)
    27. {
    28. cout<<"A"<<i;
    29. }
    30. else
    31. {
    32. cout<<"(";
    33. Traceback(i,s[i][j],s);
    34. Traceback(s[i][j]+1,j,s);
    35. cout<<")";
    36. }
    37. }
    38. int main(){
    39. int n,n1,m1,i,j=2;
    40. int p[N]={0};
    41. int m[N][N]={0};
    42. int s[N][N]={0};
    43. cout<<"Please enter the number of matrices:"<<endl;
    44. cin>>n;
    45. for(i=1;i<=n;i++){
    46. cout<<"Please enter No "<<i<<"Rows and columns of matrix (n1 m1 format):";
    47. cin>>n1>>m1;
    48. if(i==1){
    49. p[0]=n1;
    50. p[1]=m1;
    51. }
    52. else{
    53. p[j++]=m1;
    54. }
    55. }
    56. cout<<endl<<"Record matrix rows and columns:"<<endl;
    57. for(i=0;i<=n;i++){
    58. cout<<p[i]<<"\t";
    59. }
    60. cout<<endl;
    61. MatrixChain(p,n,m,s);
    62. cout<<endl<<"The minimum degree matrix of matrix multiplication is:"<<endl;
    63. for(i=1;i<=n;i++){
    64. for(j=1;j<=n;j++){
    65. cout<<m[i][j]<<"\t";
    66. }
    67. cout<<endl;
    68. }
    69. cout<<endl<<"The position matrix of matrix multiplication disconnection is:"<<endl;
    70. for(i=1;i<=n;i++){
    71. for(j=1;j<=n;j++){
    72. cout<<s[i][j]<<"\t";
    73. }
    74. cout<<endl;
    75. }
    76. cout<<endl<<"The minimum times of matrix multiplication are:\n"<<m[1][n]<<endl;
    77. cout<<endl;
    78. cout<<"Disconnected position:"<<endl;
    79. Traceback(1,n,s);
    80. return 0;
    81. }

     

     

  • 相关阅读:
    我换了一圈儿,又回来了!
    macOS Sonoma 14beta 7(23A5337a)更新发布,附黑/白苹果系统镜像
    C++模板类和友元
    Java基础--》做个简易的计算器
    大模型应用开发:手把手教你部署并使用清华智谱GLM大模型
    UnityShader入门精要——PBS基于物理的渲染
    Java并发常见面试题(二)
    电容笔和Apple pencil区别有什么?双十一值得入手的电容笔推荐
    h2database BTree 设计实现与查询优化思考
    统计语言模型笔记
  • 原文地址:https://blog.csdn.net/ycq0_9/article/details/127560730