矩阵链相乘【DP】

> Description
在这里插入图片描述


> Input
n表示矩阵的个数(<=100)
n+1个数,表示矩阵(<=100)

> Output
最小的乘法次数


> Sample Input
5
5 10 4 6 10 2

> Sample Output
348


> 解题思路
按照题意,这几个数只能结合相乘,不能交换相乘,也就是不能打乱数的排列顺序(因为这个矩阵链的乘法hin是奇怪,一交换答案就不一样了)。
然后老师让我们算了一下它有多少种乘法的方式,数字十分之巨大,为catalan数,所以不能用递归,这时DP就出现了。

循环中,d为长度,i、j为边界(i起始,j结束),k为划分。
接下来,由于假设给出的数为5 10 4 6 10 2们,那么就有5个矩阵5·10,10·4,4·6,6·10,10·2;
5·10与10·4的矩阵可以合成一个5·4大小的矩阵,乘法的次数为5·10·4,

状态转移方程:

f[i][j]=min(f[i][j],f[i][k-1]+f[k][j]+a[i]*a[k]*a[j+1])

也就是把i到j分为两段,假如数5 10 4 6(10),k在数10上,就表示把这4个矩阵划分成两段:5·10和10·4 4·6 6·10。 按照我神奇地理解,就是f[i][j]表示数从i到j,矩阵就是从i到j中每一个数乘后一个数所组成的矩阵

解释一下状态转移方程:就是分为两段,把第一段内的次数和第二段内的次数相加,再加上两段最后组成一个矩阵的次数。f[i][k-1]在上面已经解释过,为了组成i*(i+1),…,(k-1)*k;a[i]*a[k]*a[j+1]中(j+1)是因为每一串数中的最后一个数还要跟这一串数后面的一个数组成一个矩阵。


> 代码

#include<iostream>
#include<cstdio>
using namespace std;
const int inf=1000000;
int n,a[105],f[105][105];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n+1;i++)
	{
		scanf("%d",&a[i]); f[i][i]=0;
	}
	for(int d=2;d<=n;d++)
	 for(int i=1;i<=n-d+1;i++)
	 {
	 	int j=i+d-1;
	 	f[i][j]=inf;
	 	for(int k=i+1;k<=j;k++)
	 	 f[i][j]=min(f[i][j],f[i][k-1]+f[k][j]+a[i]*a[k]*a[j+1]);
	 }
	printf("%d",f[1][n]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/85011768