zoukankan      html  css  js  c++  java
  • 动态规划之矩阵链相乘

     题目:n个矩阵连乘,求最少的乘法运算次数以及结合方式

       假设矩阵A为r1*r2,矩阵B为r2*r3,所以M=A*B=r1*r2*r3。当有多个矩阵相乘的时候,矩阵以不同的方式结合的时候其运算次数是不同的。

    例如:M=M1   *     M2    *    M3    *    M4

                    [5*20]   [20*50]    [50*1]    [1*100]

    ((M1*M2)*M3)*M4=5000+250+500=5750

    而M1*(M2*(M3*M4))=5000+100000+10000=115000

    如果按照(M1*(M2*M3)*M4)=1000+100+500=1600

    上面的例子说明根据不同的结合顺序,运算的次数是不同的。现在我们就是要求通过哪种顺序所进行的乘法运算次数最少,并且求出运算最少的次数是多少。

    算法思想:

      记Mi*Mi+1*Mi+2*...*Mj为mij,矩阵的大小为:M1为r1*r2,M2为r2*r3,M3为r3*r3,M4为r4*r5。r1,r2,r3,r4,r5分别为5,20,50,1,100.

     (1)首先计算矩阵相乘个数为2的3种情况。

    m12=M1*M2=r1*r2*r3=5000,m23=r2*rr*r4,m34=r3*r4*r5=1000,m34=5000

     (2)计算相乘矩阵个数为3的2种情况

    m13=M1*M2*M3,目标是求出m13的乘法运算次数最小值。m13=min{M1*m23+r1*r2*r4,m12*M3+r1*r3*r4}=min{1100,5250}=m12*M3+r1*r3*r4=1100

    同理 m24=M2*M3*M4=min{M2*m34+r2*r3*r,m23*M4+r2*r4*r5}=min{10500,3000}=3000;

    (3)最后计算相乘矩阵个数为4的最终结果:

      m14=min(m13*M4+r1*r4*r5,m12*m34+r1*r3*r4,M1*m24+r1*r2*r5)={3000+10000 ,5000+5000,+25000,1100+500}=1600

    算法如下

    #include <iostream>
    
    using namespace std;
    
    int r[100],com[100][100];
    
    int course(int i,int j)
    {
        int u,t;
        if(i==j)
            return 0;
        if(i==j-1)
        {
            com[i][j]=i;
            return r[i]*r[i+1]*r[i+2];
        }
        else
        {
            u=course(i,i)+course(i+1,j)+r[i]*r[i+1]*r[j+1];
            com[i][j]=i;
            for(int k=i;k<j;k++)
            {
                t=course(i,k)+course(k+1,j)+r[i]*r[k+1]*r[j+1];
                if(t<u)
                {
                    u=t;
                    com[i][j]=k;
                }
            }
            return u;
        }
    }
    
    
    int main()
    {
        int n;
        printf("input n:");
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&r[i]);
        printf("min=%d
    ",course(1,n-1));
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                printf("%d ",com[i][j]);
            printf("
    ");
        }
        return 0;
    }

    com适用于保存矩阵的结合方式的com[i][j]=k,表示的是mik*mkj的时候进行乘法的次数最少

    递归调用的过程如下:



    1-2,2-3,3-4等子问题都被递归调用了2次,子问题存在重复。可以采用备忘录方法解决该问题,设置一个全局变量m[i][j[,存储已经计算过的course(i,j)的值,下次调用的时候直接使用。

    非递归算法

      非递归的算法计算过程和算法主要思想里面的一致。运算的矩阵的个数从少到多慢慢增加。

      for(int i=1;i<n;i++)
        {
            m[i][i]=0;
            m[i][i+1]=r[i]*r[i+1]*r[i+2];
            com[i][i+1]=i;
        }
        m[n][n]=0;
        //动态规划
        for(int s=2;s<n;s++)
            for(int i=1;i<=n-s+1;i++)
            {
                j=i+s;
                m[i][j]=m[i][i]+m[i+1][j]+r[i]*r[i+1]*r[j+1];
                com[i][j]=i;
                for(int k=i+1;k<j;k++)
                {
                    t=m[i][k]+m[k+1][j]+r[i]*r[k+1]*r[j+1];
                    if(t<m[i][j])
                        m[i][j]=t;
                    com[i][j]=k;
                }
    
            }





    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    kafka window环境搭建
    oracle 日期格式化和数据去重
    angular $http服务详解
    Spring框架之beans源码完全解析
    计算机经典书籍100本分享
    Thinking in Java 4th(Java编程思想第四版)文档、源码、习题答案
    Spring框架之事务源码完全解析
    TCP/IP网络协议层对应的RFC文档
    Spring源码深度解析之事务
    Spring框架之websocket源码完全解析
  • 原文地址:https://www.cnblogs.com/gaot/p/4859840.html
Copyright © 2011-2022 走看看