您的位置:首页 > 其它

动态规划算法——矩阵乘法的顺序安排

2013-05-26 15:59 169 查看
动态是解决递归过程的大量冗余计算的缺点,其采用把子问题的答案系统的记录在一个表中,当计算后面的问题是用到前面的结果可以直接到表中查找,而无需再递归重新计算。

比如:斐波那契数是一个常见的递归计算过程,采用递归算法程序效率非常低。递归算法是模仿递归过程的,计算F(n),存在一个对F(n-1)和F(n-2)的调用,求解F(n-1),要对F(n-2)、F(n-3)的调用,存在2次对F(n-2)的计算、F(n-3)计算3次,F(n-4)计算5次等等。随着n的增大,对底层的计算次数呈现指数增长。其实计算F(n)时只要F(n-1)和F(n-2),因此只要记录最近计算的两个斐波那契数就OK。动态规划的思想就是把底层计算的结果存储以供上一层计算时使用,这样就避免了重复的计算。

下面介绍动态规划如何用于解决矩阵乘法的顺序安排问题:

例子:4个矩阵A、B、C、D,大小分别为:50*10、10*40、40*30、30*5,乘积ABCD可以任意加括号在计算其值。不同的计算顺序乘法次数不一样。

(A((BC)D)):16000次乘法;(A(B(CD))):10500次乘法;((AB)(CD)):36000次乘法;(((AB)C)D):87500次乘法;((A(BC))D):34500次乘法。

找到最优的计算次序可以有效的降低计算量。

给定矩阵A1,A2,...An,如何找到其计算最少的次数和最优的计算顺序?

(A1A2...Ai)(Ai+1....An)其中1<=i<=n,找出其中最少的乘法次数就是A1....An的最优解。对于A1...Ai;Ai+1...An可以采用同样的算法找出最优的乘法次数。现在取矩阵序列的任一段进行分析:Ai....Aj,m[i][j]是其乘法所需要的最少乘法次数,(Ai...Ak)(Ak+1...Aj)其中i<=k<j,左边所用的乘法次数m[i][k]、右边所要的乘法次数m[k+1][j]。

所以m[i][j]=min{ m[i][k]+m[k+1][j]+c[i-1]c[k]c[j] }其中c[i]表示第i个矩阵的列数。当i=1,j=n就找到了整体矩阵相乘的最少次数。

dynamic.h

#pragma once
#include<iostream>
#include<vector>
using namespace std;
class matrix
{
public:
void insert(int num,string s);//输入第一个矩阵的行数、和所有矩阵的列数。
void optmatrix();    //选择最优的计算方法:最少的计算次数和计算顺序
void show();       //输出最小的计算次数和计算顺序
void track(int i,int j);//寻找最优计算次序
private:
vector<int> c;    //保存输入矩阵第一个行数和所有矩阵的列数
vector<string> str;
vector<vector<long> >m;//保存计算最少次数
vector<vector<int> >lastchange;//矩阵乘法结合划分位置

};


dynamic.cpp

#include "stdafx.h"
#include"dynamic.h"
#include<iostream>
#include<vector>
#include<limits>
using namespace std;
void matrix::insert(int num,string s)//mun数组的列数,s对应数组的名称
{
c.push_back(num);
str.push_back(s);
}
void matrix::optmatrix()
{
int size=c.size()-1;
m.resize(c.size());
lastchange.resize(c.size());
for(int i=0;i<c.size();i++)
{
m[i].resize(c.size());
lastchange[i].resize(c.size());
}
for(int i=0;i<c.size();i++)//m[i,j]表示i位置到j位置矩阵乘积最少次数
{
m[i][i]=0;
lastchange[i][i]=0;
}
/*
下面求解矩阵相乘乘法次数最少,是采用由底向上计算,先求解所有相邻的2个矩阵最少的乘法次数,然后再求解3个相邻的矩阵乘法次数,依次类推。
直到所有矩阵都在一起相乘的最少乘法次数。
例如:A1 A2 A3 A4 ;先求解:A1*A2、A2*A3、A3*A4,的乘法次数。然后再求:A1*A2*A3、A2*A3*A4最少的乘法次数,计算三个相乘时要用到前面2个相乘
的结果。最后求解:A1*A2*A3*A4,其求解用到前面的结果
*/
for(int k=1;k<size;k++)//k=right-left
for(int left=1;left<=size-k;left++)
{
int right=left+k;
m[left][right]=numeric_limits<long>::max();
for(int i=left;i<right;i++)
{
long temp=m[left][i]+m[i+1][right]+c[left-1]*c[i]*c[right];
if(temp<m[left][right])
{
m[left][right]=temp;
lastchange[left][right]=i;
}
}
}
}
void matrix::show()
{
optmatrix();
int n=c.size()-1;
vector<string>::iterator it=str.begin();
cout<<"最小的运算次数为:"<<m[1]
<<endl;
cout<<"计算顺序:"<<endl;
track(1,n);
cout<<endl;
}
void matrix::track(int i,int j)
{
if(i==j)
{
cout<<str[i];
return;
}
else
{
cout<<"(";
track(i,lastchange[i][j]);
track(lastchange[i][j]+1,j);
cout<<")";
}}

Algorithm-dynamic1.cpp

//动态规划实现矩阵乘法的顺序安排
#include "stdafx.h"
#include"dynamic.h"
#include<iostream>
#include<vector>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
matrix m;
m.insert(50," ");//第一个矩阵的行数
m.insert(10,"A");//10列数,A矩阵的名
m.insert(40,"B");
m.insert(30,"C");
m.insert(5,"D");
m.show();
return 0;
}


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