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;
                }
    
            }





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

  • 相关阅读:
    ....
    CodeForces 375A(同余)
    POJ 2377 Bad Cowtractors (最小生成树)
    POJ 1258 AgriNet (最小生成树)
    HDU 1016 Prime Ring Problem(全排列)
    HDU 4460 Friend Chains(bfs)
    POJ 2236 Wireless Network(并查集)
    POJ 2100 Graveyard Design(尺取)
    POJ 2110 Mountain Walking(二分/bfs)
    CodeForces 1059B Forgery(模拟)
  • 原文地址:https://www.cnblogs.com/gaot/p/4859840.html
Copyright © 2011-2022 走看看