1. 程式人生 > >矩陣鏈相乘【DP】

矩陣鏈相乘【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; }