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

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

    比如:斐波那契数是一个常见的递归计算过程,采用递归算法程序效率非常低。递归算法是模仿递归过程的,计算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][n]<<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;
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值