原题网址
题目描述
假设我们要用标准的矩阵乘法来计算 M 1 , M 2 , M 3 M_1,M_2,M_3 M1,M2,M3三个矩阵的乘积 M 1 M 2 M 3 M_1M_2M_3 M1M2M3,这三个矩阵的维度分别是 2 × 10 , 10 × 2 , 2 × 10 2\times10,10\times2,2\times10 2×10,10×2,2×10,如果把 M 1 , M 2 M_1,M_2 M1,M2相乘,然后再与 M 3 M_3 M3相乘,那么要 2 × 10 × 2 + 2 × 2 × 10 = 80 2\times10\times2+2\times2\times10=80 2×10×2+2×2×10=80,如果代之以用 M 2 , M 3 M_2,M_3 M2,M3相乘的结果去成 M 1 M_1 M1,那么矩阵乘法的次数变成了 10 × 2 × 10 + 2 × 10 × 10 = 400 10\times2\times10+2\times10\times10=400 10×2×10+2×10×10=400,执行 M 1 ( M 2 M 3 ) M_1(M_2M_3) M1(M2M3)耗费的时间是执行乘法 ( M 1 M 2 ) M 3 (M_1M_2)M_3 (M1M2)M3的 5 5 5倍。
格式
输入格式
n
n
n表示矩阵的个数
(
≤
100
)
(\le100)
(≤100)
n
+
1
n+1
n+1个数,表示矩阵
(
≤
100
)
(\le100)
(≤100)
输出格式
最小的乘法次数
样例
输入样例
5
5 10 4 6 10 2
输出样例
348
解题思路
一般来说,顺序数等于这个
n
n
n个矩阵每一种可能的途径放置括号数的方法数。设
f
(
n
)
f(n)
f(n)是求
n
n
n个知阵乘积的所有放置括号的方法数,假定要进行下面的乘法:
(
A
1
A
2
.
.
.
A
k
)
×
(
A
k
+
1
A
k
+
2
.
.
.
A
n
)
(A_1A_2...A_k)\times (A_{k+1}A_{k+2}...A_n)
(A1A2...Ak)×(Ak+1Ak+2...An)
那么,对于前
k
k
k个矩阵有
f
(
k
)
f(k)
f(k)对于中的每一种方法,可对余下的
f
(
n
−
k
)
f(n-k)
f(n−k)个矩阵放置括号的方法,总共有
f
(
k
)
×
f
(
n
−
k
)
f(k)\times f(n-k)
f(k)×f(n−k)种方法。由于可以假设
k
k
k是
1
1
1到
n
−
1
n-1
n−1中任意值,对于
n
n
n个矩阵放置括号弧的所有方法数由
f
(
n
)
=
∑
k
=
1
n
−
1
f
(
n
)
f
(
n
−
k
)
f(n)=\sum^{n-1}_{k=1}f(n)f(n-k)
f(n)=∑k=1n−1f(n)f(n−k)
给出。显然,两个矩阵相乘只有一种方法,三个矩阵相乘有两种方法。因此
f
(
2
)
=
1
,
f
(
3
)
=
2
f(2)=1,f(3)=2
f(2)=1,f(3)=2,为了使递推有意义,令
f
(
1
)
=
1
f(1)=1
f(1)=1。我们可以证明
f
(
n
)
=
C
2
n
−
2
n
−
1
/
n
f(n)=C^{n-1}_{2n-2}/n
f(n)=C2n−2n−1/n
这个递推式就产生的CATALAN数(即卡特兰数)
百度链接
1
,
1
,
2
,
5
,
14
,
42
,
132
,
429
,
1430
,
4862
,
16796...
1,1,2,5,14,42,132,429,1430,4862,16796...
1,1,2,5,14,42,132,429,1430,4862,16796...
因此,
10
10
10个矩阵相乘存在
4862
4862
4862种方法。
矩阵
A
A
A和
B
B
B是可乘的条件是矩阵
A
A
A的列数等于矩阵
B
B
B的行数。若
A
A
A是一个
p
×
q
p\times q
p×q的矩阵,
B
B
B是一个
q
×
r
q\times r
q×r的矩阵,则其乘积
C
=
A
B
C=AB
C=AB是一个
p
×
r
p\times r
p×r矩阵。在计算
C
C
C的标准算法中,主要计算量在三重循环,总共需要
p
×
q
×
r
p\times q\times r
p×q×r次数成。
3
×
2
2
×
2
3
×
2
3\times2\ \ \ \ 2\times2\ \ \ \ \ 3\times2
3×2 2×2 3×2
1
2
2
1
8
1
1\ \ \ \ \ 2\ \ \ \ 2\ \ \ \ \ 1\ \ \ \ \ 8\ \ \ \ \ 1
1 2 2 1 8 1
2
1
∗
3
0
=
7
3
2\ \ \ \ \ 1*3\ \ \ \ \ 0=7\ \ \ \ \ 3
2 1∗3 0=7 3
0
1
3
0
0\ \ \ \ \ 1\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 3\ \ \ \ \ 0
0 1 3 0
将矩阵连乘积
A
i
A
i
+
1
…
A
j
A_iA_{i+1}…A_j
AiAi+1…Aj简记为
A
[
i
:
j
]
A[i:j]
A[i:j]。设最优次序在矩阵
A
k
A_k
Ak和
A
k
+
1
A_{k+1}
Ak+1A之间将矩阵链断开,
1
≤
k
<
n
1\le k<n
1≤k<n,则完全加括号的方式为
(
(
A
1
…
A
k
−
1
)
(
A
k
…
A
n
)
)
((A_1…A_{k-1})(A_k…A_n))
((A1…Ak−1)(Ak…An))。计算
F
[
1
]
[
n
]
F[1][n]
F[1][n]的一个最优次序所包含的计算矩阵子链
F
[
1
]
[
k
−
1
]
F[1][k-1]
F[1][k−1]和
F
[
k
]
[
n
]
F[k][n]
F[k][n]的次序也是最优的。因此,矩阵连乘积计算次序问题的最优解包含着其子问题的最优解。
f
[
i
]
[
j
]
=
m
i
n
{
f
[
i
]
[
k
−
1
]
+
f
[
k
]
[
j
]
+
r
i
r
k
r
j
+
1
}
(
i
<
k
≤
j
)
f[i][j]=min\{f[i][k-1]+f[k][j]+r_ir_kr_{j+1}\}(i<k\le j)
f[i][j]=min{f[i][k−1]+f[k][j]+rirkrj+1}(i<k≤j)
而本问题的问题求解则为:
f
[
1
]
[
n
]
=
m
i
n
{
f
[
1
]
[
k
−
1
]
+
f
[
k
]
[
n
]
+
r
1
r
k
r
n
+
1
}
f[1][n]=min\{f[1][k-1]+f[k][n]+r_1r_kr_{n+1}\}
f[1][n]=min{f[1][k−1]+f[k][n]+r1rkrn+1}
Code
#include<iostream>
#include<istream>
#include<ostream>
#include<sstream>
#include<fstream>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
const int maxn=100,inf=2147483647;
int n,m[maxn*2],f[maxn*2][maxn*2];
void init() {
ios::sync_with_stdio(false); // 快读
cin.tie(); // 快读
cin>>n;
for(int i=1;i<=n+1;i++) cin>>m[i];
}
int main() {
init();
for(int i=1;i<=n;i++) f[i][i]=0;
for(int i=1;i<n;i++) {
for(int j=1;j<=n-i;j++) {
int k=i+j;
f[j][k]=inf;
for(int l=j+1;l<=k;l++) f[j][k]=min(f[j][k],f[j][l-1]+f[l][k]+m[j]*m[k+1]*m[l]);
}
}
cout<<f[1][n];
return 0;
}