矩阵
描述
\(N(2 \le N \le 100)\) 个矩阵相乘,求进行乘法的最少次数。
我们认为两个矩阵\(A(m \times n) \times B(n \times p)\) 的乘法次数为 \(m \times n \times p\) 次。
格式
输入格式
第一行是整数 \(N\)。
接下来 \(N\) 行是对每个矩阵的描述,一行两个整数 \(a,b~(1 \le a,b \le 50)\),\(a\) 表示行,\(b\) 表示列。
输入确保能够相乘。
输出格式
一行输出最少乘法次数。
样例
样例输入
3
50 10
10 20
20 5
样例输出
3500
题解
这题思路说实话不是特别好找,主要就是要认识到矩阵之间不同的相乘顺序会导致最终乘法次数的不同。
\(f[i][j]\) 表示表示从第 \(i\) 个矩阵乘到第 \(j\) 个矩阵的最小乘法次数,即第 \(i, i+1, i+2, \dots \ , j-1, j\) 个矩阵相乘的最小乘法次数。
那么在我们该考虑怎样进行松弛,也就是该怎么列出状态转移方程。
这就是这题的精髓了:区间DP。用类似于 \(RMQ\) 算法中 \(st\) 算法和 \(Floyd\) 算法的思想,枚举一个断点 \(k\),那么我们可以得到状态转移方程为:
\[f[i][j] = \min (f[i][j],~f[i][k]+f[k+1][j] + (a[i] \times b[k] \times b[j]))
\]
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 110
using namespace std;
int n, f[N][N];
// f[i][j]表示从第i个矩阵乘到第j个矩阵的最小乘法次数
struct Matrix
{
int x, y;
}mtx[N];
int main()
{
memset(f, 0x3f, sizeof(f));
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d%d", &mtx[i].x, &mtx[i].y);
f[i][i] = 0;
}
for(int i = n; i; i--)
{
for(int j = 1; j <= n; j++)
for(int k = i; k < j; k++)
f[i][j] = min(f[i][j], f[i][k] + f[k+1][j] + mtx[i].x*mtx[k].y*mtx[j].y);
}
printf("%d", f[1][n]);
return 0;
}