【问题描述】使用动态规划算法解矩阵连乘问题,具体来说就是,依据其递归式自底向上的方式进行计算,在计算过程中,保存子问题答案,每个子问题只解决一次,在后面计算需要时只要简单查一下得到其结果,从而避免大量的重复计算,最终得到多项式时间的算法。
【输入形式】在屏幕上输入第1个矩阵的行数和第1个矩阵到第n个矩阵的列数,各数间都以一个空格分隔。
【输出形式】矩阵连乘A1…An的最少数乘次数和最优计算次序。
【样例1输入】
30 35 15 5 10 20 25
【样例1输出】
15125
((A1(A2A3))((A4A5)A6))
【样例说明】
输入:第1个矩阵的行数和第1个矩阵到第6个矩阵的列数,以一个空格分隔。
输出:矩阵连乘A1…An的最少数乘次数为15125,最优计算次序为((A1(A2A3))((A4A5)A6))。
【评分标准】根据输入得到准确的输出。
基本思想:
矩阵连乘可以抽象为:
dp[i][j]:从矩阵i到矩阵j连乘所需要的最小乘数
则可以推理出等式:
dp[i][j] = dp[i][k] + dp[k+1][j] + a[i-1]*a[k]*a[j]
(其中a[i]是i矩阵的列数)
可明显发觉dp[i][j]的子问题也是最优解
因此可以使用递归的方式求解
并且可发展为动态规划来进行算数优化
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1005;
int t = 0, n = -1;
int a[maxn] = {0};
int dp[maxn][maxn] = {0};
int bac[maxn][maxn] = {0};
void TraceBack(int l, int r) {
if(l == r) {
printf("A%d", l);
}
else {
printf("(");
TraceBack(l, bac[l][r]);
TraceBack(bac[l][r]+1, r);
printf(")");
}
}
int main() {
while(scanf("%d", &a[++n]) != EOF) {} n--;
for(int k = 2; k <= n; ++k) {
for(int i = 1; i <= n-k+1; ++i) {
int j = i+k-1;
dp[i][j] = dp[i+1][j] + a[i-1] * a[i] * a[j], bac[i][j] = i;
for(int m = i+1; m < j; ++m) {
t = dp[i][m] + dp[m+1][j] + a[i-1] * a[m] * a[j];
if(t < dp[i][j]) {
dp[i][j] = t, bac[i][j] = m;
}
}
}
}
printf("%d\n", dp[1][n]);
TraceBack(1, n);
return 0;
}