实验报告
课程名称 《算法分析与设计》 实验日期 2021年 4 月 26 日 至 2021 年 4 月 26 日
学生姓名 林泓佺 所在班级 计算机193 学号 20019212212088
实验名称 矩阵链乘法
实验地点 勤园13号楼208 同组人员 林泓佺
1.问题
[有n个矩阵排成一行,矩阵Ai的列和Ai+1的行数保证相等
规定两个矩阵(mx,my)相乘的花费为两矩阵的基本运算即 mx的行数mx的列数my的列数
询问如何通过选择矩阵相乘的先后顺序来得到最小的花费]
2.解析
[对于这个问题,我们可以采用动态规划中的区间dp,主要是通过合并小区间的最优解进而得出整个大区间上最优解。对于矩阵链乘,我们把所有矩阵看作一个长度为n的区间,那么可以得到对于区间长度大于1的每个矩阵一定都是原来两个矩阵的乘积,就是两个已经得到的矩阵再加上两个矩阵相乘的花费,就可以看作两个小区间的值再加上乘积。
可以推出这个递推式:dp[l][r] = dp[l][k] + dp[k + 1][r] + a[l - 1] * a[k] * a[r]]
7
8 2 7 5 6 3 9 8
过程:
区间长 = 1
m[1, 1] = 0 s[1, 1] = 1
m[2, 2] = 0 s[2, 2] = 2
m[3, 3] = 0 s[3, 3] = 3
m[4, 4] = 0 s[4, 4] = 4
m[5, 5] = 0 s[5, 5] = 5
m[6, 6] = 0 s[6, 6] = 6
m[7, 7] = 0 s[7, 7] = 7
区间长 = 2
m[1, 2] = 112 s[1, 2] = 1
m[2, 3] = 70 s[2, 3] = 2
m[3, 4] = 210 s[3, 4] = 3
m[4, 5] = 90 s[4, 5] = 4
m[5, 6] = 162 s[5, 6] = 5
m[6, 7] = 216 s[6, 7] = 6
区间长 = 3
m[1, 3] = 150 s[1, 3] = 1
m[2, 4] = 130 s[2, 4] = 3
m[3, 5] = 195 s[3, 5] = 3
m[4, 6] = 225 s[4, 6] = 5
m[5, 7] = 360 s[5, 7] = 5
区间长 = 4
m[1, 4] = 226 s[1, 4] = 1
m[2, 5] = 190 s[2, 5] = 3
m[3, 6] = 384 s[3, 6] = 5
m[4, 7] = 426 s[4, 7] = 5
区间长 = 5
m[1, 5] = 238 s[1, 5] = 1
m[2, 6] = 244 s[2, 6] = 5
m[3, 7] = 579 s[3, 7] = 5
区间长 = 6
m[1, 6] = 388 s[1, 6] = 1
m[2, 7] = 454 s[2, 7] = 5
区间长 = 7
m[1, 7] = 582 s[1, 7] = 1
m[1, 7] = 582
实际算式:
(A1(((A2A3)(A4A5))(A6A7)))
3.设计
[#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
const int INF=1e7+10;
int n;
int dp[1010][1010];
int a[maxn], s[1010][1010];
void matrix_chain_mul(){
printf(“过程:\n”);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dp[i][j]=INF;
}
}
printf(“区间长 = %d\n”, 1);
for(int i = 1; i <= n; ++ i) {
dp[i][i] = 0; s[i][i] = i;
printf(“m[%d, %d] = %d s[%d, %d] = %d\n”, i, i, dp[i][i], i, i, s[i][i]);
}
printf("\n");
for(int i = 2; i <= n; ++ i) {
printf(“区间长 = %d\n”, i);
for(int j = i; j <= n; ++ j) {
int l = j - i + 1;
for(int k = s[l][j - 1]; k <= s[l + 1][j]; ++ k) {
int tmp = dp[l][k] + dp[k + 1][j] + a[l - 1] * a[k] * a[j];
if(dp[l][j] > tmp){
dp[l][j] = tmp;
s[l][j] = k;
}
}
printf(“m[%d, %d] = %-6d s[%d, %d] = %d\n”, l, j, dp[l][j], l, j, s[l][j]);
}
printf("\n");
}
}
void dfs(int l, int r) {
if(l == r) printf(“A%d”, l);
else {
printf("(");
dfs(l, s[l][r]);
dfs(s[l][r] + 1, r);
printf(")");
}
}
int main(){
scanf("%d", &n);
for(int i = 0; i <= n; ++ i) scanf("%d", &a[i]);
matrix_chain_mul();
printf(“m[%d, %d] = %d\n”, 1, n, dp[1][n]);
puts(“实际算式:”);
dfs(1, n);
puts("");
return 0;
}
/*
6
5 9 8 2 4 5 9
5
2 5 12 9 5 10
7
8 2 7 5 6 3 9 8
*/
]
4.分析
[时间复杂度为O(n3)
空间复杂度为O(n2)
]
5.源码
[github源码地址:https://github.com/lhqbalabala/sf4.26]