1. 问题
2. 解析
-
b o t t o m − u p : bottom-up: bottom−up: 自底向上。从最底层的小区间开始逐个合并,最后合并到最大的区间。
-
d i v i d e : divide: divide: 区间的分割。根据分割点k,我们可以分割为两个区间,例如 [ i , j ] [i,j] [i,j] 可以分割为 [ i , k ] [i,k] [i,k] 和 [ k + 1 , j ] [k+1,j] [k+1,j] 两个区间。
-
t r a n s f e r : transfer: transfer: 状态的转移,或可以说是区间的合并。由于 [ i , k ] [i,k] [i,k] 和 [ k + 1 , j ] [k+1,j] [k+1,j] 的区间长度肯定比 [ i , j ] [i,j] [i,j] 要小, 由于我们升序枚举区间长度,所以当前这两个区间的状态值已经是最优的,又由于大区间由子区间合并而成,所以我们可以取其中某几个子区间合并的最优的状态值作为当前 [ i , j ] [i,j] [i,j] 的最优状态值。
-
例如: P = < 30 , 35 , 15 , 5 , 10 , 20 , 25 > , n = 6 P=<30,35,15,5,10,20,25>, n=6 P=<30,35,15,5,10,20,25>,n=6
-
A1:30*35, A2:35*15, A3:15*5, A4:5*10, A5:10*20, A6:20*25
-
m [ i ] [ j ] m[i][j] m[i][j] 代表区间 [ i , j ] [i,j] [i,j] 最优状态值, s [ i ] [ j ] s[i][j] s[i][j] 代表区间 [ i , j ] [i,j] [i,j] 的分割点
-
(1)
r=1
m[1,1]=0;
m[2,2]=0;
m[3,3]=0;
m[4,4]=0;
m[5,5]=0;
m[6,6]=0;
-
(2)
r=2,i=1,2,3,4,5; j=2,3,4,5,6
m[1,2]=30*35*15=15750;
m[2,3]=35*15*5=2625;
m[3,4]=15*5*10=750;
m[4,5]=5*10*20=1000;
m[5,6]=10*20*25=5000
-
(3)
r=3,i=1,2,3,4; j=3,4,5,6
m[1,3]=min{m[1,2]+m[3,3]+(A1A2)A3,m[1,1]+m[2,3]+A1(A2A3)};s[1,3]=1
m[2,4]=min{m[2,3]+m[4,4]+(A2A3)A4,m[2,2]+m[3,4]+A2(A3A4)};s[2,4]=3
m[3,5]=min{m[3,4]+m[5,5]+(A3A4)A5,m[3,3]+m[4,5]+A3(A4A5)};s[3,5]=3
m[4,6]=min{m[4,5]+m[5,6]+(A4A5)A6,m[4,4]+m[5,6]+A4(A5A6)};s[4,6]=5
-
(4)
r=4, i=1,2,3; j=4,5,6
m[1,4]=min{m[1,1]+m[2,4]+A1(A2A3A4),m[1,2]+m[3,4]+(A1A2)(A3A4),m[1,3]+m[4,4]+(A1A2A3)A4};s[1,4]=3
m[2,5]=min{m[2,2]+m[3,5]+A2(A3A4A5),m[2,3]+m[4,5]+(A2A3)(A4A5),m[2,4]+m[5,5]+(A2A3A4)A5};s[2,5]=3
m[3,6]=min{m[3,3]+m[4,6]+(A3A4A5)A6,m[3,4]+m[5,6]+(A3A4)(A5A6),m[3,5]+m[6,6]+(A3A4A5)A6};s[3,6]=3
-
(5)
r=5,i=1,2; j=5,6
m[1,5]=min{m[1,1]+m[2,5]+A1(A2A3A4A5),m[1,2]+m[3,5]+(A1A2)(A3A4A5),m[1,3]+m[4,5]+(A1A2A3)(A4A5);m[1,4]+m[5,5]+(A1A2A3A4)A5};s[1,5]=3
m[2,6]=min{m[2,2]+m[3,6]+A2(A3A4A5A6),m[2,3]+m[4,6]+(A2A3)(A4A5A6),m[2,4]+m[5,6]+(A2A3A4)(A5A6);m[2,5]+m[6,6]+(A2A3A4A5)A6};s[2,6]=3
-
(6)
r=6,i=1; j=6
m[1,6]=min{m[1,1]+m[2,6]+A1(A2A3A4A5A6),m[1,2]+m[3,6]+(A1A2)(A3A4A5A6),m[1,3]+m[4,6]+(A1A2A3)(A4A5A6);m[1,4]+m[5,6]+(A1A2A3A4)(A5A6);m[1,5]+m[6,6]+(A1A2A3A4A5)A6};s[1,6]=3
-
s[1,6]=3 (A1A2A3)(A4A5A6), s[1,3]=1,s[1,6]=5 (A1(A2A3))((A4A5)A6)
-
结果:(A1(A2A3))((A4A5)A6)
3. 设计
矩阵链乘算法:
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1e3+10;
int n,m,x;
vector<int>p;
int dp[N][N],sep[N][N];
//矩阵链乘法
void matrixChain() {
//枚举区间长度
for (int d=1;d<=n;d++) {
//枚举区间左端点
for (int i=1;i<=n-d;i++) {
//区间右端点
int j=i+d;
//枚举区间分割点
for (int k=i;k<j;k++) {
//p[i-1]代表Ai的行数,p[k]代表Ak的的列数,p[j]代表Aj的列数
int temp = dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j];
if (dp[i][j] > temp) {
dp[i][j] = temp;
sep[i][j] = k;
}
}
}
}
cout<<dp[1][n]<<endl;
}
//输出矩阵链乘法的方案
void printChain(int l,int r) {
if (l==r) {
cout<<"A"<<l;
return;
}
cout<<"(";
printChain(l,sep[l][r]);
printChain(sep[l][r]+1,r);
cout<<")";
}
void run() {
memset(dp,inf,sizeof dp);
cin>>n;
for (int i=0;i<=n;i++) {
cin>>m;
p.push_back(m);
dp[i][i] = 0;
}
matrixChain();
printChain(1,n);
}
int main() {
run();
return 0;
}
/*
6
30 35 15 5 10 20 25
*/
4. 分析
5. 源码
https://github.com/a894985555/Algorithm/tree/main/%E7%9F%A9%E9%98%B5%E9%93%BE%E4%B9%98%E6%B3%95