确定n个矩阵连乘积 A1A2A3…An 的计算次序,使得按照这一次序计算矩阵连乘积,需要的"数乘"次数最小。
思路:
递归定义
d
p
[
i
,
j
]
dp[i,j]
dp[i,j]如下:
对于i=j时的平凡问题,矩阵链只包含唯一的矩阵
A
i
A_i
Ai,因此不需要做任何标量乘法运算。所以,对所有i=1,2,…,n,
d
p
[
i
,
i
]
=
0
dp[i,i]=0
dp[i,i]=0。
若i<j,我们利用步骤1中得到的最优子结构来计算m[i,j]。
我们假设A(i)A(i+1)…A(j)的最优括号化方案的分割点在矩阵A(k)和A(k+1)之间,其中i<=k<j。
那么,
d
p
[
i
,
j
]
dp[i,j]
dp[i,j]就等于计算A(i…k)和A(k+1…j)的代价加上两者相乘的代价的最小值。
由于矩阵Ai的大小为x*y,易知A(i…k)和A(k+1…j)相乘的代价为
A
i
x
∗
A
k
y
∗
A
j
y
A_ix*A_ky*A_jy
Aix∗Aky∗Ajy次标量乘法运算。
因此,我们得到
d
p
[
i
,
j
]
=
d
p
[
i
,
k
]
+
d
p
[
k
+
1
,
j
]
+
A
i
x
∗
A
k
y
∗
A
j
y
dp[i,j]=dp[i,k]+dp[k+1,j]+ A_ix*A_ky*A_jy
dp[i,j]=dp[i,k]+dp[k+1,j]+Aix∗Aky∗Ajy
此公式假定最优分割点k是已知的,但实际上我们不知道。
但k只有j-i种可能的取值,即k=i,i+1,…,j-1。
由于最优分割点必在其中,我们只需检查所有可能情况,找到最优者即可。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f;
int main()
{
int t;cin>>t;
while(t--){
ll dp[101][101];
memset(dp,INF,sizeof(dp));
int n;cin>>n;
struct Node{int x,y;}stu[n];
for(int i=0;i<n;i++) cin>>stu[i].x>>stu[i].y;
for(int i=0;i<n;i++) dp[i][i]=0;
//链长度
for(int len=1;len<n;len++){
//矩阵头
for(int i=0;i+len<n;i++){
//矩阵尾
int j=i+len;
for(int k=i;k<j;k++){
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+stu[i].x*stu[k].y*stu[j].y);
}
}
}
cout<<dp[0][n-1]<<endl;
}
}