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