动态规划之矩阵链乘法-matrix-chain muliplication problem(dp)

一,问题描述

矩阵链乘法问题(matrix-chain multiplication problem)可描述如下:给定n个矩阵的链<A1,A2,...,An>,矩阵Ai的规模为p(i-1)×p(i) (1<=i<=n),求完全括号化方案,使得计算乘积A1A2...An所需标量乘法次数最少

   因为括号方案的数量与n呈指数关系,所以通过暴力搜索穷尽所有可能的括号化方案来寻找最优方案是一个糟糕策略。


二,代码

如上,此题如果暴力破解的话,就要计算的是每一种括号情况,假如用递归的思想,

那么对于如果要选择a1,a2,利用组合的知识,可以知道可以选出的是n-1种情况。接

下来,将选出的计算结果作为一个整体,那么剩下的(n-1)个矩阵就有n-2中可以选

择的情况。

利用组合排列的知识,可以得到最终暴力破解的次数将会是n(n-1)(n-2)..2*1

这是指数性质的,处理较大的n的时候,这显然不现实。


于是乎就有了动态规划的解法,即从链的长度由小到大的计算每一层,选出每一层的

最小的,参与下一层的计算,这样就免去了很多的重复计算,这也就是动态规划中的

由底向上的方法。


代码如下:

/*矩阵链式乘法*/
#include<iostream>
#include<vector> 
#include<iomanip>

class Solution{
	private:
		int n;                                    //the number of the matrix
		std::vector<int> scale;                   //the scale chain of the matrix,start with i=0
		std::vector<std::vector<int> > cost;            //the cost of every cases,start with (1,1)
		std::vector<std::vector<int> > site;            //the location of the shortest case,start with (1,2)
	public:
		void test();                                    //this function is used th test the application
		void getScale();
		int workCost();
		int showResult(std::vector<std::vector<int> > &c,int i,int j);
};

/*get the scale of the chain*/
void Solution::getScale()
{
	int temp=1;
	std::cout<<"please input the scale of every matric in order:(use 0 to make the end) ";
	while(temp!=0)
	{
	std::cin>>temp;
	if(temp==0) break;
	scale.push_back(temp);
    }
    //l=scale.size();
    n=scale.size()-1;
    
    /*nitialization vector*/ 
    //for(int i=1;i<=n;i++)
    //for(int j=1;j<=n;j++)
    std::vector<std::vector<int> > cost1(n+1,std::vector<int> (n+1));
    std::vector<std::vector<int> > site1(n+1,std::vector<int> (n+1));
    cost=cost1;
    site=site1; 
    
    /*in the question ,if i==j,that mean the two matrix is equal,so the result is 0*/
    /*for(int i=1;i<n;i++)
    cost[i][i]=0;*/
    /*because of the vector's features,so the code is not necessary*/ 
}

/*get the cost and the schme*/
int Solution::workCost()
{
	int j,q;
	//case 1: when the two operands is the same ,that the m[i,i]=0,the work has been done
	
	//case 2:when no same
	for(int l=2;l<=n;l++)               //from the minimum length to be bigger
	  for(int i=1;i<=n-l+1;i++)
	  {
	  	j=i+l-1;
	  	//cost[i][j]=cost[i+1][j]+scale[i-1]*scale[i]*scale[j];
	  	
	  	//to work out in the length of l,wherever the k(site) is ,what the cost is;
	  	for(int k=i;k<=j-1;k++)
	  	{
	  	//	std::cout<<"h ";
		  q=cost[i][k]+cost[k+1][j]+scale[i-1]*scale[k]*scale[j];
		  if (k==i) { cost[i][j]=q;  site[i][j]=k; continue; }
	  	  if(q<cost[i][j])
	  	 {
	  		  cost[i][j]=q;                       //get the lowest cost
	  		  site[i][j]=k;                       //get the site of the "lowest cost"
		  }
	    }
	  }
	  test();
	  /*show the result*/
	  showResult(site,1,n);
}

void Solution::test()
{
	//display the variable
	std::cout<<"VARIABLE IS: ";
	std::cout<<n;
	std::cout<<std::endl;
	 
	//display the scale
	std::cout<<"SCALE IS: ";
	for(int i=0;i<=n;i++)
	std::cout<<scale[i]<<" ";
	std::cout<<std::endl;
	
	//display the cost
	std::cout<<"COST IS: "<<std::endl;
	for(int j=1;j<=n;j++)
	{
	for(int k=1;k<=n;k++)
	std::cout<<std::setw(10)<<cost[j][k]<<" ";
	std::cout<<std::endl;
    }
    std::cout<<std::endl;
	 
	//display the site 
	std::cout<<"SITE IS: "<<std::endl;
	for(int l=1;l<=n-1;l++)
	{
	for(int m=2;m<=n;m++)
	std::cout<<site[l][m]<<" ";
	std::cout<<std::endl;
    }
    std::cout<<std::endl;
}
/*to let you know the answer*/
int Solution::showResult(std::vector<std::vector<int> > &c,int i,int j)
{
	if(i==j) std::cout<<"A["<<i<<"]";
	else {
	std::cout<<'(';
	showResult(site,i,site[i][j]);
	showResult(site,site[i][j]+1,j);
	std::cout<<')';
    }
}

int main()
{
	Solution test;
	test.getScale();
	test.workCost();
	//test.showResult(test.site,1,test.n);
}

测试用例为scale={5,10,3,12,5,50,6};

测试结果为:


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
矩阵乘问题是一个经典的动态规划问题,其目标是找到一种最优的方式来计算给定的一组矩阵的连乘积。这个问题可以通过动态规划算法来解决。 动态规划算法的基本思想是将问题分解成更小的子问题,并使用已知的信息来计算更大的问题。在矩阵乘问题中,我们可以将问题分解成计算两个矩阵的乘积的子问题,并使用已知的信息来计算更大的问题。 具体来说,我们可以定义一个二维数组m,其中m[i][j]表示从第i个矩阵到第j个矩阵的最小计算代价。我们还可以定义一个二维数组s,其中s[i][j]表示从第i个矩阵到第j个矩阵的最优计算次序。 接下来,我们可以使用以下递归公式来计算m和s: m[i][j] = 0 (i = j) m[i][j] = min{m[i][k] + m[k+1][j] + ri*ck*cm} (i <= k < j) 其中,ri和ci分别表示第i个矩阵的行数和列数,cm表示两个矩阵相乘的计算代价。 使用上述递归公式,我们可以计算出所有的m[i][j]和s[i][j]。最终,我们可以通过s数组来构造出最优的计算次序,并使用m数组来计算最小的计算代价。 下面是一个Python实现的例子: ```python def matrix_chain_order(p): n = len(p) - 1 m = [[0] * n for i in range(n)] s = [[0] * n for i in range(n)] for l in range(2, n+1): for i in range(n-l+1): j = i + l - 1 m[i][j] = float('inf') for k in range(i, j): q = m[i][k] + m[k+1][j] + p[i]*p[k+1]*p[j+1] if q < m[i][j]: m[i][j] = q s[i][j] = k return m, s def print_optimal_parens(s, i, j): if i == j: print("A{}".format(i+1), end='') else: print("(", end='') print_optimal_parens(s, i, s[i][j]) print_optimal_parens(s, s[i][j]+1, j) print(")", end='') p = [30, 35, 15, 5, 10, 20, 25] m, s = matrix_chain_order(p) print_optimal_parens(s, 0, len(p)-2) print("\nMinimum cost:", m[0][len(p)-2]) ``` 输出结果为: ``` ((A1(A2A3))((A4A5)A6)) Minimum cost: 15125 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值