当前位置: 代码网 > it编程>软件设计>算法 > 动态规划——矩阵连乘积问题(个人学习用)

动态规划——矩阵连乘积问题(个人学习用)

2024年08月06日 算法 我要评论
(1).找出最优解的性质(2).动态规划方程(3).自底向上计算最优值。

一、设计动态规划算法的步骤

(1).找出最优解的性质

(2).动态规划方程

(3).自底向上计算最优值

二、矩阵连乘积问题

计算三个矩阵abc的成绩,由于矩阵乘法的性质,不同计算顺序导致的乘法运算量可能相差悬殊。即(ab)c 和a(bc)的运算量差距很大。

a:行数*列数 50*10 b:10*40 c:40*30

乘法运算次数:

(ab)c=(50*10*40)+50*40*30 =80000

a(bc)=50*10*30+(10*40*30)=27000

第二种计算方法的运算量是明显小于第一种的

三、分析最优解的结构

使用a[i,j]代表ai,ai+1...aj的连乘积,做一个断点k,i<=k<j,k将矩阵的连乘积分割为两部分,ai,ai+1...ak,ak+1...aj。以此,对乘积ai,ai+1...aj的完全加括号的代价就是计算ai,ai+1...ak,ak+1...aj的代价之和,再加上两者相乘的代价。

即:(ai,ai+1...ak)+(ak+1...aj)+pi-1pkpj

ai的维数为 ai-1*temp ai-1的原因是p[i]从0开始存储

//p[i]为行数,temp为列数
for(i=0;i<=n-1;i++)
		scanf("%d%d",&p[i],&temp);

若ai,ai+1...aj的一个最优完全加括号方式是以k为断点,分割矩阵,则ai,ai+1...ak的子链必须是它的一个最优完全加括号方式。反之,若存在ai,ai+1...ak的一个代价更小的最优完全加括号方式,则它替换到ai,ai+1...aj中则会产生另一个最优解。这样一来,任何最优解都包含子问题的最优解。

四、建立递归关系

a[i,j]代表ai,ai+1...aj的连乘积,m[i][j]代表a[i][j]的最少次数。

a[1,n]代表a1,a2...an的连乘积,m[1][n]代表a[1,n]的最优解。

i,起始位置,j,终止位置。

当i=j,代表矩阵链只包含一个矩阵,a[1,1]代表矩阵链中只包含矩阵a1。

则m[i][i]=0.

i<j,在ai,ai+1...aj中加一个断点k,i<=k<j,则m[i][j]等于子乘积a[i,k]和a[k+1,j]的和在加上两个矩阵相乘的乘法运算次数(代价),乘法运算次数就是m*n 矩阵a * n*p 矩阵b = m *p 矩阵c

图片来源:

https://www.cnblogs.com/beatrice7/p/4149639.html

定义数组s[i][j]保存k的值。

#include<bits/stdc++.h>
using namespace std;
#define num 51
int p[num];//行列数p[i-1]行数,p[i]为列数
int m[num][num];//保存最优解
int s[num][num];//保存断点k的值
int lookupchain(int i,int j)
{
	if(m[i][j]>0)return m[i][j];//m[i][j]存了子问题的运算结果
	if(i==j)return 0;//只含一个矩阵的情况。
	int u = lookupchain(i,i)+lookupchain(i+1,j)+p[i-1]*p[i]*p[j];//递推公式,以i为第一个断点
	s[i][j] = i;
	for(int k=i+1;k<j;k++)//从i后找不同断点的情况,保存最小值为最优解m[i][j]
	{
		int t = lookupchain(i,k)+lookupchain(k+1,j)+p[i-1]*p[k]*p[j];
		if(t<u){u=t;s[i][j]=k;}
	}
	m[i][j]=u;
	return u;
}
矩阵a1a2a3a4

a5

a6
行列数50*1010*4040*3030*55*2020*15
下标0123456
5010403052015

 

 五、构建最优解

(a[i,k])(a[k+1,j]),令s[i][j]=k

则a[1,n]的最优加括号方式为(a([1,s[1][n]))(a(s[1][n]+1,n))

void traceback(int i,int j)
{
	if(i==j)printf("a%d",i);
	else
	{
		printf("(");
		traceback(i,s[i][j]);
		traceback(s[i][j]+1,j);
		printf(")");
	}
}

完整代码为:

#include<bits/stdc++.h>
using namespace std;
#define num 51
int p[num];
int m[num][num];
int s[num][num];
int lookupchain(int i,int j)
{
	if(m[i][j]>0)return m[i][j];
	if(i==j)return 0;
	int u = lookupchain(i,i)+lookupchain(i+1,j)+p[i-1]*p[i]*p[j];
	s[i][j] = i;
	for(int k=i+1;k<j;k++)
	{
		int t = lookupchain(i,k)+lookupchain(k+1,j)+p[i-1]*p[k]*p[j];
		if(t<u){u=t;s[i][j]=k;}
	}
	m[i][j]=u;
	return u;
}
void traceback(int i,int j)
{
	if(i==j)printf("a%d",i);
	else
	{
		printf("(");
		traceback(i,s[i][j]);
		traceback(s[i][j]+1,j);
		printf(")");
	}
}
int main()
{
	int n;
	scanf("%d",&n);
	int i,temp;
	for(i=0;i<=n-1;i++)
		scanf("%d%d",&p[i],&temp);
	p[n]=temp;
	memset(m,0,sizeof(m));
	lookupchain(1,n);
	printf("%d\n",m[1][n]);
	traceback(1,n);
	return 0;
}
/*
input:
6
50 10
10 40
40 30
30 5
5 20
20 15
output:
15750
((a1(a2(a3a4)))(a5a6))
*/

本博客资料、代码来源于清华大学出版社算法设计与分析,本博客仅用于个人学习,可能存在纰漏,敬请批评指正。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com