试题 算法提高 矩阵乘法

资源限制

内存限制:256.0MB C/C++时间限制:3.0s Java时间限制:9.0s Python时间限制:15.0s

问题描述

  有n个矩阵,大小分别为a0*a1, a1*a2, a2*a3, ..., a[n-1]*a[n],现要将它们依次相乘,只能使用结合率,求最少需要多少次运算。
  两个大小分别为p*q和q*r的矩阵相乘时的运算次数计为p*q*r。

输入格式

  输入的第一行包含一个整数n,表示矩阵的个数。
  第二行包含n+1个数,表示给定的矩阵。

输出格式

  输出一个整数,表示最少的运算次数。

样例输入

3
1 10 5 20

样例输出

150

数据规模和约定

  1<=n<=1000, 1<=ai<=10000。

单纯记录一下自己的见解。

首先这是一个区间DP(动态规划)算法,而且应该还属于比较简单的那种,但是我一开始的疑惑是这个很像acwing 上面的石子合并问题

282. 石子合并 - AcWing题库

但是我一开始还没有去学区间DP的时候就在思考题目怎么做的时候,首先阅读题目有点难度这里的比如样例

1 10 5 20

指的应该是:

第一个矩阵是1行10列

第二个矩阵是10行5列

第三个矩阵是5行20列

那样的话计算应该是三个合并啊,而看到的题解又多数是两个数合并

首先区间DP的常规模板

dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+matrix[i]*matrix[j]*matrix[k];

 你如果要求得i-j段的最小计算次数,那么也是需要找出来两个矩阵的

第一个矩阵 i行k列

第二个矩阵 k行j列

这两个矩阵如何得到?

合并i-k,合并k-j

我们发现就是每一次矩阵运算合并下来的新矩阵的结果总是消去了中间的数字而保留了两边的数字,所以说在合并i-k,k-j的之后得到的结果i,k,j这三个矩阵的属性数还是被保存下来的。

所以说总的最小计算次数就是合并i-k的最小次数,合并k-j的最小次数,加起来之后加上合并i,k,j的计算次数。

在细节方面 k是可以取到i+1的因为这样就是i与k之间是没有去合并其他的矩阵属性数的,而合并的全是k与j之间的同样的k可以取到j-1的原因也是如此。

#include <iostream>
#include <algorithm>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
long long int dp[1010][1010];
long long int nums[1010];//必须设置ll不然会超长度
int main(int argc, char** argv) 
{
	int n,i,j,k,len;
	cin>>n;
	for(i=1;i<=n+1;i++)
	{
		cin>>nums[i];
	}
	for(len=3;len<=n+1;len++)//因为合并区间的计算至少三个数字,不像石子合并只要两个就可以合成一堆
	{
		for(i=0;i+len-1<=n+1;i++)//计算固定长度的区间的合并结果
		{
			j=i+len-1;
			dp[i][j]=0x3f3f3f3f3f3f3f3f3f;//设置为一个很大的值
			for(k=i+1;k<=j-1;k++)//k值可以取到i+1与j-1
			{
				dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+nums[i]*nums[k]*nums[j]);//见上
			}
		}
	}
	cout<<dp[1][n+1];//因为dp[i][j]表示的是从i到j的计算最少次数,所以打印这个
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值