还是说矩阵连乘问题,在用动态规划来做的时候,是一种自底向上的路线,要接触m[1,n]就要先从一个矩阵的时候,2个连乘的时候,3个连乘的时候,开始一步步求,填好表,然后才可以求出n个矩阵连乘。
其实在想这道题目的时候,一般人们也会想用暴力的方法解决,就是用递归来做,算法就像下面这个样子
RECURSIVE-MATRIX-CHAIN(p, i, j)
1 if i = j
2 then return 0
3 m[i, j] ← ∞
4 for k ← i to j - 1
5 do q ← RECURSIVE-MATRIX-CHAIN(p, i, k)
+ RECURSIVE-MATRIX-CHAIN(p,k + 1, j)
+ pi-1 pk pj
6 if q < m[i, j]
7 then m[i, j] ← q
8 return m[i, j]
这个算法就是直接利用递归式
来写的,这个算法的时间复杂度是指数级别的,非常耗时,在下面的图中显示了这个递归算法的递归树
在图中可以看出,在递归过程中,有很多子问题是重复求的,浪费时间就是浪费在重复解了很多已经解决过的子问题。现在我们要做的就是,通过一个表来记录下已经求出来的那些子问题的解,然后在递归过程中,去检查要求解的子问题的值是否已经在表中记录,是的话,那么就不用去解,而是直接在表中读取即可,这就是备忘录技术,也是经常说的记忆化搜索。下面是利用备忘录技术修改的上面直接递归的代码
#include <iostream>
using namespace std;
#define INF 999999999
int m[101][101];
int LookUp_Chain(int p[],int i,int j)
{
if(m[i][j] < INF)
return m[i][j];
if(i == j)
m[i][j]=0;
else
{
int q;
for(int k=i;k<j;k++)
{
q=LookUp_Chain(p,i,k)+LookUp_Chain(p,k+1,j)+p[i-1]*p[k]*p[j];
if(q < m[i][j])
m[i][j]=q;
}
}
return m[i][j];
}
int Memoized_Matrix_Chain(int p[],int n)
{
n=n-1;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
m[i][j]=INF;
return LookUp_Chain(p,1,n);
}
int main()
{
int n;
int p[101];
cin>>n;
for(int i=0;i<n;i++)
cin>>p[i];
int _min=Memoized_Matrix_Chain(p,n);
cout<<_min<<endl;
return 0;
}
上面这个代码是 POJ1651这道题的解答,前一篇日志也有写,是用动态规划的思想写的,大家可以对比一下。