动态规划-矩阵连乘

动态规划常常用来解决,具有最优子结构,重叠子问题的对象。

最优子结构: 即通过分析问题,将问题分解为多个子问题。然后每个子问题继续分解为更多子问题。从底往上求出最有值,由最优值确定最优解。

重叠子问题: 在计算过程中不同子问题可能都会计算某个值。若每个子问题都去求解同一个值,浪费时间。动态规规划对每一个子问只求解一次,而后将其保留在一个表格中。当再次需要求解此子问题时,只需常数时间去查看下是否已经计算过。

总体思路: 构造最优子结构->自底向上求出子问题最优值->由最优值确定最终的最优解 。

矩阵连乘计算次数与矩阵间的计算顺序有关。因此要求出最优的计算次数。就得确定好矩阵的计算顺序。

最优子结构: https://images0.cnblogs.com/blog/328951/201308/01232112-3e04f4695adb47f38db1b930702ea0cd.x-png

代码:

/**
   @优化矩阵连乘计算次数(动态规划)
   @author  狂热的coder
*/
#include<iostream>
#include<algorithm>
#define NUM_SIZE 50
using namespace std;
void matrixChain(int *p,int n,int m[NUM_SIZE][NUM_SIZE],int s[NUM_SIZE][NUM_SIZE]){
    for(int i = 1;i<=n;i++){            //m[i][j]表示矩阵A(i)~A(j)相乘计算次数,s[i][j]记录A(i)~A(j)相乘中的分割点。
        m[i][i] = 0;                   //矩阵本身相乘次数为0
    }
    for(int i = 2;i<=n;i++){           //i为连乘矩阵的个数
       for(int j = 1;j<=n-i+1;j++){   //j表示连乘矩阵中的第一个
           int k = j+i-1;            //k表示连乘矩阵中的最后一个(末 = 始+个数-1)
           m[j][k] = m[j+1][k]+p[j-1]*p[j]*p[k];
           s[j][k] = j;            //j暂时作为断点
           /*这两层循环是起始为Aj,结尾为Ak,长度为i的矩阵段Ai~Aj*/
           for(int r = j+1;r<k;r++){  //r作为断点,循环求出Aj~Ak中的最小数乘次数
               int t = m[j][r]+m[r+1][k]+p[j-1]*p[r]*p[k]; 
               if(t<m[j][k]){
                   m[j][k] = t;
                   s[j][k] = r;
               }
           }
       }
    }
}
int main(){
    int n;
    cin>>n;                    //矩阵个数
    int p[NUM_SIZE] = {0};
    for(int i = 0;i<=n;i++){  //各矩阵的行数,最后一矩阵的列数.
       cin>>p[i];
    }
    int m[NUM_SIZE][NUM_SIZE],s[NUM_SIZE][NUM_SIZE];
    cout<<"矩阵间计算次数信息:"<<endl;
    matrixChain(p,n,m,s);
    for(int i = 1;i<=n;i++){
         for(int j = 1;j<=n;j++){
             cout<<m[i][j]<<" ";
         }
         cout<<endl;
    }
    cout<<"分割点记录信息:"<<endl;
    for(int i = 1;i<=n;i++){
         for(int j = 1;j<=n;j++){
             cout<<s[i][j]<<" ";
         }
         cout<<endl;
    }
    return 0;
}
/*
6
30 35 15 5 10 20 25
*/

由矩阵间信息可知矩阵1~6的最优计算顺序为:1~6断开点为3。分为(1~3), (4~6),1~3断开点为1。分为(1), (2~3)。类似的往下推即可求出最优值。

( (A1(A2*A3) )*( (A4*A5)*A6 )

附上备忘录方法:

#include<iostream>
#include<cstdio>
#define N 6
using namespace std;
int m[N+1][N+1];//最优解
int s[N+1][N+1];
int p[N+1]= {30,35,15,5,10,20,25};
int beiwanglu(int i, int j) {
    if(m[i][j]>0)
        return m[i][j];
    if(i==j)
        return 0;
    int u = beiwanglu(i,i)+beiwanglu(i+1,j)+p[i-1]*p[i]*p[j];
    s[i][j] = i;
    for(int k=i+1; k<j; k++) {
        int temp=beiwanglu(i,k)+beiwanglu(k+1,j)+p[i-1]*p[k]*p[j];
        if(temp<u){
            u = temp;
            s[i][j] = k;
        }
    }
    m[i][j] = u;
    return u;
}

void  f(int n){
    int i,j;
    for(i=1; i<=n; i++)
        for(j=i;j<=n; j++)
            m[i][j]=0;
     beiwanglu(1,n);
     for(int i = 1;i<=n;i++){
         for(int j = 1;j<=n;j++){
             cout<<m[i][j]<<" ";
         }
         cout<<endl;
    }
     for(int i = 1;i<=n;i++){
         for(int j = 1;j<=n;j++){
             cout<<s[i][j]<<" ";
         }
         cout<<endl;
    }
}
int main(){
    //printf("%d\n",f(N));
    f(N);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lfb637/article/details/80324229