动态规划常常用来解决,具有最优子结构,重叠子问题的对象。
最优子结构: 即通过分析问题,将问题分解为多个子问题。然后每个子问题继续分解为更多子问题。从底往上求出最有值,由最优值确定最优解。
重叠子问题: 在计算过程中不同子问题可能都会计算某个值。若每个子问题都去求解同一个值,浪费时间。动态规规划对每一个子问只求解一次,而后将其保留在一个表格中。当再次需要求解此子问题时,只需常数时间去查看下是否已经计算过。
总体思路: 构造最优子结构->自底向上求出子问题最优值->由最优值确定最终的最优解 。
矩阵连乘计算次数与矩阵间的计算顺序有关。因此要求出最优的计算次数。就得确定好矩阵的计算顺序。
最优子结构: 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; }