矩阵连乘问题

ⅰ亾dé卋堺 提交于 2020-01-22 03:15:11

由于矩阵乘法运算满足结合率,如果有矩阵A、B、C、D连续相乘,那么 A(BCD) = (AB)(CD) = … 。
所以可以找到一个好的加括号顺序使得计算量减少。可以使用动态规划问题解决。

动态规划解题步骤:
1, 找到最优子结构
即子问题最优可以令父问题也达到最优。本例中,若想(ABCDEFG)*(HIJKLMN)计算步骤最少,那么ABCDEFG加括号方式一定是最优的,同理HIJKLMN加括号也是最优的。可以尝试使用分治法(递归)先求出最优解。
2,使用空间换时间
使用一个空间保存子问题的解,另一个空间保存求解过程,计算某个子问题时,先判断子问题是否已经解决,如果已经解决,则直接返回已保存的解,否则计算这个子问题的解并存下。即,将上一步分治的计算结果存在一个数组里,并将分治的过程保存在另一个数组里。
3,找到最优解
根据保存的求解过程,找到最优解。

运行结果:

在这里插入图片描述
代码如下

#include <iostream>
using namespace std;

/* 递归求解最优的加括号方式
 * i 子问题下界
 * j 子问题上界
 * k 存储子问题的解
 * s 存储子问题求解过程
 * */
int mulSqlAct(int w[], int h[], int i, int j, int** k, int** s){
	if(j - i <= 1){
		return 0;
	}

	//动态规划:把子问题的解存下
	if(k[i][j] == 0){
		unsigned int min = 0xFFFFFFFF;
		unsigned int minIndex = 0;
		for(int p = i + 1; p < j; p++){

			int lValue = mulSqlAct(w, h, i, p, k, s);;
			int rValue = mulSqlAct(w, h, p, j, k, s);;
			int count = lValue + rValue + w[i] * h[j - 1] * w[p];
			if(count < min){
				min = count;
				minIndex = p;
			}
		}
		k[i][j] = min;
		s[i][j] = minIndex;
	}
	return k[i][j];
}

/* 找到最好的加括号方式
 * 即根据求解过程,找到问题的最优解
 * */
void trace(int** s, int i, int j){
	if(j - i <= 1){
		cout << i;
		return;
	}

	cout << "(";
	trace(s, i, s[i][j]);
	cout <<")" ;
	cout << "*";
	cout << "(" ;
	trace(s, s[i][j], j);
	cout << ")";
}

/* w 矩阵的长度
 * h 矩阵的宽度
 * n 相乘矩阵的个数
 * */
void mulSeq(int w[], int h[], int n){
	int** k = new int*[n + 1];
	int** s = new int*[n + 1];
	for(int i = 0; i <= n; i++){
		k[i] = new int[n + 1];
		s[i] = new int[n + 1];
		for(int j = 0; j <= n; j++){
			k[i][j] = 0;
			s[i][j] = 0;
		}
	}

	cout << "乘法运算次数:" << mulSqlAct(w, h, 0, n, k, s) << endl;
	cout << "最优加括号方式:";
	trace(s, 0, n);
}

int main()
{

	int w[] = {30, 35, 15, 5, 10, 20};
	int h[] = {35, 15, 5, 10, 20, 25};
	mulSeq(w, h, 6);
	return 0;
} 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!