算法思想
每一次的加括号会产生两个不同的乘积结果相乘,如果这两个乘积结果是最优的(计算次数最少),那么最后的计算结果也会是最优的,由此,可以分解成求解两个子问题的最优解问题,如此下去
算法实现
#include <stdio.h>
void MatrixChain(int *p,int n,int m[][10],int s[][10]){ //p数组里面存储每个矩阵的行数和列数,n是矩阵数量,m记录从i到j的最小计算量,s记录从i到j的最小计算量的断开位置
//1.对单个矩阵相乘(规模为1)的计算量进行初始化,也就是只有一个矩阵时,计算量为0
for(int i = 1;i<=n;i++){
m[i][i] = 0;
}
//2.对规模大于2(相乘的矩阵数量大于2)的计算量进行计算
for(int r = 2;r<=n;r++){ //控制规模大小
for(int i = 1;i<=n-r+1;i++){ //遍历当前规模的每一种
int j = i+r-1; //记录乘到最后的那个矩阵的位置
m[i][j] = m[i][i] + m[i+1][j] + p[i-1] * p[i] * p[j]; //通过dp方程,暂存当前的计算量
s[i][j] = i; //保存当前的断开的位置
for(int k = i+1;k<j;k++){ //遍历其他的断开位置,选出最优的断开位置
int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j]; //算出当前断开点的计算量
if(t<m[i][j]){
m[i][j] = t; //更新当前的计算量
s[i][j] = k; //更新当前的断开点
}
}
}
}
}
//输出最优解
void Traceback(int i,int j,int s[][10]){
if(i == j){
return;
}
Traceback(i,s[i][j],s);
Traceback(s[i][j]+1,j,s);
printf("%d,%d and %d,%d",i,s[i][j],s[i][j]+1,j);
printf("\n");
}
int main(){
int p[10] = {30,35,15,5,10,20,25};
int m[10][10];
int s[10][10] = {0};
MatrixChain(p,6,m,s);
Traceback(1,6,s);
// printf("%d ",s[1][6]);
// printf("%d ",m[1][6]);
for(int i = 1;i<7;i++){
for(int j = 1;j<7;j++){
printf("%d ",s[i][j]);
}
printf("\n");
}
return 0;
}