您的位置:首页 > 其它

动态规划 矩阵连乘问题

2016-12-04 15:12 633 查看

什么是动态规划



看到把原始问题划分成一系列子问题,我们很容易想到分治算法,但是对于分治算法,很可能会遇到子问题被重复使用

就像下面这个矩阵连乘,分解为子问题就会出现三个重复子问题,用分治算法时,就会重复计算相同的子问题,使程序效率变得低下

所以,这就是动态规划的用武之地:对于一个问题,可分为多个相关子问题,子问题的解被重复使用



矩阵连乘问题

对于矩阵连乘,假设A为10 * 100 的矩阵, B为100 * 5 的矩阵,C为5 * 50的矩阵,那么有两种情况:

1、(A * B) * C 一共要乘 10 * 100 * 5 + 10 * 5 * 50 = 7500次

2、A * (B * C) 一共要乘 100 * 5 * 50 + 10 * 100 * 50 = 750000次

可以看到,不同顺序的相乘,就会有不同的时间复杂度,动态规划就是要来求一个最优解。

把这个括号的位置设为k,那么(A * B) * C 的k值就为2,表示A 和 B的矩阵先乘;A * (B * C) 的 k 值为 1, 表示B 和 C的矩阵相乘。

那么我们要做的就是如何确定这个k值,使得矩阵相乘具有最优解。



m[i, j]是指矩阵 i 到 矩阵 j 相乘的最小乘法数

p之间相乘是指拆分的矩阵之间的相乘

对于A * B * C:

m[1,3] = m[1,1] + m[2, 3] + p0 * p1 * p3 的意思是 A * (B * C)

m[1,3] = m[1,2] + m[3, 3] + p0 * p2 * p3 的意思是 (A * B) * C

也可以用这个图来理解





例如求m[1, 3] 就是 求 m[1, 1] 和 m[2, 3] 或者 求 m[1, 2] 和 m[3, 3。

代码实现

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

#define SIZE 100
#define INF 999999999

int p[SIZE];
int m[SIZE][SIZE];  //存放矩阵链计算的最优值,d[i][j]为第i个矩阵到第j个矩阵的矩阵链的最优值

int Best_DP(int n)
{

memset(m, 0, sizeof(m));

int len;

for (len = 1; len <= n; len++)
{
int i, j, k;
for (i = 1, j = i+len; j <= n; i++, j++)
{
int min = INF;
for (k = i; k < j; k++)
{
int count = m[i][k] + m[k+1][j] + p[i-1] * p[k] * p[j];
if (count < min)
{
min = count;
}
}
m[i][j] = min;
}
}
return m[1]
;
}

int main(void)
{
int n;
while (scanf("%d", &n) != EOF)
{
int i;
for (i = 0; i <= n; i++)
{
scanf("%d", &p[i]);
}

printf("%d\n", Best_DP(n));
}
return 0;
}


这里需要注意的是:

n是指相乘的矩阵数目

p用来存放各矩阵的信息: 用p[i - 1] 和 p[i]来表示第i个矩阵的行和列,例如 A为10 * 100 的矩阵, B为100 * 5 的矩阵,C为5 * 50的矩阵,则p[0] = 10 , p[1] = 100, p[2] = 5 , p[3] = 50

m[i, j]用来表示i 到 j矩阵相乘的最优解

时间复杂性和空间复杂性

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: