问题描述:
给定n个矩阵的链<A1,A2,…,An>,矩阵Ai的规模为p(i-1)×p(i) (1<=i<=n),求完全括号化方案,使得计算乘积A1A2…An所需标量乘法次数最少。
动态规划的第一步是寻找最优子结构,然后就可以利用这种子结构从子问题的最优解构造出原问题的最优解。在矩阵链乘法问题中,我们假设A(i)A(i+1)…A(j)的最优括号方案的分割点在A(k)和A(k+1)之间。那么,继续对“前缀”子链A(i)A(i+1)…A(k)进行括号化时,我们应该直接采用独立求解它时所得的最优方案。
递归实现:
①对于i=j的情况下,显然有m=0,不需要做任何标量乘法运算。所以,对于所有的i=1、2…n,m[i,i] = 0.
②当i < j的情况,就按照最优括号化方案的结构特征进行计算m[i,j]。假设最优括号化方案的分割点在矩阵Ak和Ak+1之间,那么m的值就是Ai…k和Ak+1…j的代价加上两者量程的代价的最小值。即。该公式的假设是最优分割点是已知的,但是实际上不知道。然而,k只有j-i中情况取值。由于最优分割点k必定在i~j内取得,只需要检查所有可能的情况,找到最优解即可。可以得出一个递归公式
代码实现【C++】
#include <iostream>
using namespace std;
#define N 6
#define MAXVALUE 1000000
void matrix_chain_order(int *p,int len,int m[N+1][N+1],int s[N+1][N+1]);
void print_optimal_parents(int s[N+1][N+1],int i,int j);
int main()
{
int p[N+1] = {30,35,15,5,10,20,25};
int m[N+1][N+1]={0};
int s[N+1][N+1]={0};
int i,j;
matrix_chain_order(p,N+1,m,s);
cout<<"m value is: "<<endl;
for(i=1;i<=N;++i)
{
for(j=1;j<=N;++j)
cout<<m[i][j]<<" ";
cout<<endl;
}
cout<<"s value is: "<<endl;
for(i=1;i<=N;++i)
{
for(j=1;j<=N;++j)
cout<<s[i][j]<<" ";
cout<<endl;
}
cout<<"The result is:"<<endl;
print_optimal_parents(s,1,N);
return 0;
}
void matrix_chain_order(int *p,int len,int m[N+1][N+1],int s[N+1][N+1])
{
int i,j,k,t;
for(i=0;i<=N;++i)
m[i][i] = 0;
for(t=2;t<=N;t++) //当前链乘矩阵的长度
{
for(i=1;i<=N-t+1;i++) //从第一矩阵开始算起,计算长度为t的最少代价
{
j=i+t-1;//长度为t时候的最后一个元素
m[i][j] = MAXVALUE; //初始化为最大代价
for(k=i;k<=j-1;k++) //寻找最优的k值,使得分成两部分k在i与j-1之间
{
int temp = m[i][k]+m[k+1][j] + p[i-1]*p[k]*p[j];
if(temp < m[i][j])
{
m[i][j] = temp; //记录下当前的最小代价
s[i][j] = k; //记录当前的括号位置,即矩阵的编号
}
}
}
}
}
//s中存放着括号当前的位置
void print_optimal_parents(int s[N+1][N+1],int i,int j)
{
if( i == j)
cout<<"A"<<i;
else
{
cout<<"(";
print_optimal_parents(s,i,s[i][j]);
print_optimal_parents(s,s[i][j]+1,j);
cout<<")";
}
}
结果
到此这篇关于C++动态规划算法实现矩阵链乘法的文章就介绍到这了,更多相关C++矩阵链乘法内容请搜索易知道(ezd.cc)以前的文章或继续浏览下面的相关文章希望大家以后多多支持易知道(ezd.cc)!