动态规划算法的基本要素:
- 最优子结构性质
假设A1*A2*A3*...*An在k处断开为最优,那么只需要保证A1*...*Ak和Ak*..*An两个子序列的分割也是最优,就能保证该结果是最优。
- 子问题重叠性
问题描述:
对于多个矩阵连乘,不同的分割次序会导致计算次数的不同,所以要找到最优化的分割,减少计算量。
A1 | A2 | A3 | A4 | A5 | A6 |
30*35 | 35*15 | 15*5 | 5*10 | 10*20 | 20*25 |
计算子问题的最优解并保存:
矩阵m保存子问题的最优计算量,矩阵s保存子问题的最优分割方式。
矩阵m:
矩阵s:
举例说明:
m[0][3]=7875,s[0][3]=1表示对于子问题(分割A1*A2*A3),需要的最少计算量为7875次,最优分割点在位置1,也就是分割为A1*(A2*A3)。
#include "stdafx.h"
#include<iostream>
#include<cstdlib>
using namespace std;
void MatrixChain(int *p, int n, int m[][6], int s[][6]);
void TraceBack(int i, int j, int s[][6]);
int main()
{
int n = 6;
int p[7] = { 30,35,15,5,10,20,25 };
int m[6][6] = {};
int s[6][6] = {};
for (int i = 0; i < 6; i++)
for (int j = 0; j < 6; j++)
{
m[i][j] = 0; s[i][j] = 0;
}
MatrixChain(p, n, m, s);
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 6; j++) cout << s[i][j] << "\t";
cout << endl;
}
//cout << s[0][5]<<endl;
TraceBack(0, 5, s);
system("pause");
return 0;
}
//构造最优解矩阵
void MatrixChain(int *p, int n, int m[][6], int s[][6])
{
for (int i = 0; i < n; i++) m[i][i] = 0;//将矩阵分割成单个的矩阵,此时计算量为0
for (int r = 2; r <= n; r++)//将矩阵分割为2 - n 个矩阵,计算此时的计算量
for (int i = 0; i < n-r+1; i++)
{
int j = i + r - 1;
//将矩阵连乘m[i][j]最优分割点初始化为第i个矩阵处
m[i][j] = m[i + 1][j] + p[i] * p[i+1] * p[j+1];
s[i][j] = i+1;
//寻找比初始化分割点更优的分割点
for (int k = i + 1; k <= j; k++)
{
int temp = m[i][k] + m[k + 1][j] + p[i] * p[k+1] * p[j+1];
if (temp < m[i][j]){m[i][j] = temp;s[i][j] = k+1;}
}
}
}
//递归搜索最优解
void TraceBack(int i, int j, int s[][6])
{
//查找最优解位置s[i][j]
if (i == j || i == j-1) return;//已经分出来单个矩阵,或者两个矩阵相乘的部分,不需要再进行分割
else
{
TraceBack(i, s[i][j] - 1, s);//递归分割左边部分
cout << s[i][j] << "\t";//输出分割点位置
TraceBack(s[i][j], j, s);//递归分割右边部分
}
}
参考资料
- 算法设计与分析--王晓东