动态规划—矩阵链相乘

题目描述

用加括号的方式给出最优的矩阵相乘方案

输入
多组数据输入

第一行一个整数 n n n,表示矩阵链的长度(1<=n<=300)

接下来一行 n + 1 n+1 n+1个数表示这些矩阵的行数和列数

输出
对于每组数据,输出两行,第一行为计算次数,第二行为计算方案,用加括号的方式给出最优的矩阵相乘方案

如果不幸最优方案不唯一,选择优先计算左边的矩阵

输入样例

3
10 30 5 60
3
10 20 5 4

输出样例

4500
((A1A2)A3)
1200
((A1A2)A3)

Hint
在第二组样例中,选择((A1A2)A3)时,结果为10×20×5+10×5×4=1200

选择A1(A2A3)时,结果为20×5×4 + 10×20×4 = 1200

这时选择第一种,优先计算左边的!

思路分析

对于Ai到Aj矩阵链,假设我们知道应该从Ak后面截开,则相乘次数为Ai到Ak的次数加上A(k+1)到Aj的次数加上合并次数Ai行数Ak列数Aj列数
那么让k从Ai到A(j-1)遍历,找到使相乘次数最小的k即可

动态规划填表法:设置一个dp[i][j]存储矩阵Ai到Aj相乘的最小次数
i==j时,一个矩阵不需要相乘,次数为0
i!=j时,遍历循环控制变量l=j-i等于1、2、……、n-1的所有情况,需要用的时候查表即可获得子串的相乘次数,然后做出选择
(j-i从小到大遍历,需要子串相乘次数时dp中已经存在)
设置一个s[i][j]存储k表示Ai到Aj矩阵连乘应该从k出断开,即Ai到Ak、A(k+1)到Aj

AC代码

#include<stdio.h>
#define maxnum 100000000
int a[310];
int dp[310][310]={0},s[310][310];
void chain(int a[],int n);
void paint(int i,int j);
int main()
{
	int i,n;
	while((scanf("%d",&n))!=EOF)
	{
		for(i=0;i<=n;i++)
		  scanf("%d",&a[i]);  //矩阵Ai的行列为A[i-1][i]
		chain(a,n);
		printf("%d\n",dp[1][n]);
		paint(1,n);
		printf("\n");
	}
}
void chain(int a[],int n)
{
	int i,j,l,k,temp;
	for(l=1;l<=n-1;l++)
	{
		for(i=1;i<=n-l;i++)
		{
			j=i+l;
			dp[i][j]=maxnum;
			for(k=i;k<=j-1;k++)
			{
				temp=dp[i][k]+dp[k+1][j]+a[i-1]*a[k]*a[j];
				if(temp<=dp[i][j])
				{//这里的等于体现了左边优先
					dp[i][j]=temp;
					s[i][j]=k;
				}
			}
		}
	}
}
void paint(int i,int j)
{
	if(i==j)  printf("A%d",i);
	else
	{
		printf("(");
		paint(i,s[i][j]);
		paint(s[i][j]+1,j);
		printf(")");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值