矩阵连乘问题
问题分析
最优子结构性质
假设n个矩阵连乘的最优加括号方案为(A1...Ak)(Ak+1...An))(注:此处省略了A1...Ak, Ak+1...An两个子矩阵内部的括号)。则加括号方案(A1...Ak)是子矩阵链A1...Ak的最优加括号方案,(Ak+1...An)是Ak+1...An的最优加括号方案。
证明略。但可证明该假设成立。
状态表示和递推方程
- 状态表示本质上是子问题的表征:每一个子矩阵链Ai...Aj对应一个子问题,它由开始矩阵和结束矩阵的下标决定,记为A[i:j].
- A[i,j]的最优计算次序对应的乘法次数表示为m(i,j), 1<=i, j<=n
- 原问题的最优值为m(1,n).
输入:多组测试数据,每组测试数据包括两行,第一行输入矩阵的个数n(n<1000),第二行输入n+1个数,依次表示p0,p1,p2...,pn.
输出:最少的数乘次数。
输入样例:
3
10 100 5 50
输出样例:
7500
#include <stdio.h> #include <stdlib.h> #define MaxNum 1000 long matrixChain(int matrixNum); int dim[MaxNum]; long menoTable[MaxNum][MaxNum]; //记录最优值的数组,表示理论分析部分的m int bestK[MaxNum][MaxNum]; //记录最优化分位置k的数组,表示理论分析部分的s int main() { int i, matrixNum; while(scanf("%d", &matrixNum) != EOF) //读入矩阵的数目 { for (i = 0; i <= matrixNum; ++i) { scanf("%d", &dim[i]); //读入矩阵阶的信息 } printf("%ld\n", matrixChain(matrixNum)); } return 0; } long matrixChain(int matrixNum) { int i, j, k, len; for (i = 1; i <= matrixNum; ++i) //单个矩阵的情形,定义数乘次数为0 { menoTable[i][i] = 0; } for (len = 2; len <= matrixNum; ++len) //计算长度为len的矩阵链最优值 { for (i = 1; i <= matrixNum-len+1; ++i) //矩阵连的开始矩阵下标 { j = i + len - 1; //矩阵连的结束矩阵下标 menoTable[i][j] = 1000000; //预定义一个充分大的数 for (k = i; k < j; ++k) { long ans = menoTable[i][k] + menoTable[k+1][j] + dim[i-1]*dim[k]*dim[j]; if (ans < menoTable[i][j]) { bestK[i][j] = k; menoTable[i][j] = ans; } } } } return menoTable[1][matrixNum]; }