zoukankan      html  css  js  c++  java
  • 动态规划之矩阵连乘和POJ 1651

    题目:

    设有矩阵M1,M2,M3,M4,
    其维数分别是10×20, 20×50, 50×1 和100,现要求出这4个矩阵相乘的结果。我们知道,若矩阵A的维数是q,矩阵B的维数是r,则A与B相乘后所得矩阵AB的维数是r。按照矩阵相乘的定义,求出矩阵AB中的一个元素需要做q次乘法(及q-1次加法)。这样,要计算出AB就需要做r次乘法。为简单起见,且由于加法比同样数量的乘法所用时间要少得多,故这里我们暂不考虑加法的计算量。由于矩阵连乘满足结合律,故计算矩阵连乘的方式可以有多种。

     

    例如,我们可以按M1(M2(M3M4))的方式去计算,

    也可以按(M1(M2M3))M4的方式去计算,所得结果是相同的。

    但是值得注意的是,

    按前一方式计算需要做125,000次乘法,

    而按后一方式计算只需要做2,200次乘法。

    由此可见,矩阵连乘的运算次序对于所需要的计算量

    (所需乘法次数)有着极大的影响。

    M3M4:50*1*100=5,000;M2(M3M4):20*50*100=100,000

    M1(M2(M3M4)):10*20*100=20,000

    (M2M3):20*50*1=1000;(M1(M2M3)):10*20*1=200 ;

    (M1(M2M3))M4:10*1*100=1000

    动态规划重在解决状态转移方程,设存储多个矩阵的数组为mat,行为r列为c,动态规划数组为m,m[j][i]表示[j,i]区间上矩阵连乘的最小计算量。则最终结果保存在m[0][n-1]上。状态转移方程为:

    m[j][i] = min(m[j][k] + m[k+1][i] + mat[j].r*mat[k].c*mat[i].c)
    随着k的值不同,m[j][i]保存最小的值。
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    struct MAT
    {
      int r, c;
    }mat[1005];
    int m[1005][1005];
    int main(void)
    {
        //freopen("9-6.in","r",stdin);
      int n;
      scanf("%d",&n);//矩阵个数
      for(int i=0; i<n; i++)
      {
        scanf("%d%d",&mat[i].r, &mat[i].c);
        m[i][i] = 0;//每个矩阵的行数和列数
      }
      for(int i=0; i<n; i++)  //第i列
      {
        for(int j=i-1; j>=0; j--) //第j行
        {
           int temp = 999999;
           for(int k=j; k<i; k++)
           {
                int x = m[j][k] + m[k+1][i] + mat[j].r*mat[k].c*mat[i].c;
             temp = min(temp, x);    //取不同断点寻找最优子结构
           }
           m[j][i]=temp;//表示[j,i]区间上的最优解
        }
      }
      printf("%d",m[0][n-1]);//最终结果在m[0][n-1]上
        return 0;
    }
    //2015-07-31

     掌握之后可以去刷POJ 1651

    http://poj.org/problem?id=1651

    下面是我的Ac代码,这次区间为[i, j]

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    struct mat
    {
      int r, c;
    }m[105];
    int a[105], dp[105][105];
    int main(void)
    {
        //freopen("1651.in","r",stdin);
        int n;
        scanf("%d",&n);
        for(int i=0; i<n; i++)
      {
        scanf("%d",&a[i]);
        dp[i][i] = 0;
      }
      for(int i=0; i<n-1; i++)
      {
        m[i].r = a[i];
        m[i].c = a[i+1];
      }
      n--;
      for(int i=n-2; i>=0; i--)
        for(int j=i+1; j<n; j++)
        {
            dp[i][j] = 9999999; 
          for(int k=i; k<j; k++)
          {
            int x = dp[i][k] + dp[k+1][j] + m[i].r*m[k].c*m[j].c;
            dp[i][j] = min(dp[i][j], x);
          }
        }
      printf("%d
    ",dp[0][n-1]);
        return 0;
    }
  • 相关阅读:
    C++ reference
    C++ const 限定符
    POJ 1222 EXTENDED LIGHTS OUT(高斯消元)
    poj 2185
    poj 2406
    poj 2752
    hdu 6171
    hdu 6127
    uva 3708
    hdu 6092
  • 原文地址:https://www.cnblogs.com/mycd/p/4693977.html
Copyright © 2011-2022 走看看