算法实践8 矩阵链乘法

问题:

\(A_1, A_2, \dots, A_N\)\(n\)个矩阵的序列,其中\(A_i\)\(P_{i-1} \times P_i\)阶矩阵,这个矩阵链的输入用向量\(P=<P_0,P_1,\dots,P_n>\)给出。

给定向量\(P\),确定一种乘法次序,使得基本运算的总次数达到最小。

解析

可以将括号的乘法里看作一个整体,那么两个括号合在一起,就变成了区间合并问题。

\(dp[i][j]\)为第\(i\)个矩阵乘到第\(j\)个矩阵需要的最少次数,我们枚举\(i\),\(j\)的中间值\(k\),合并\(i->k\)\(k->j\),更新最优答案,得到转移方程

\(dp[i][j]=min(dp[i][j], dp[i][k] + dp[k + 1][j] + p[i - 1]*p[j]*p[k])\)

设计

for 枚举长度 len
    for 枚举区间头 i
        for 枚举中间合并点k
            dp[i][j]=min(dp[i][j], dp[i][k] + dp[k + 1][j] + p[i - 1]*p[j]*p[k])

分析

三层循环,时间复杂度\(O(n^3)\)

源码

https://github.com/Sstee1XD/Algorithm_homework/tree/main/实验8 矩阵链乘法

#include <bits/stdc++.h>

using namespace std;

#define endl "\n"

const int inf = 0x3f3f3f3f;
const int N = 1e3 + 7;

int p[N], dp[N][N];

int n;

void solve() {
    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> p[i];
    }
    n--;
    for (int i = 1; i <= n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            dp[i][j] = inf;
        }
    }
    for (int len = 2; len <= n; ++len) {
        for (int i = 1; i + len - 1 <= n; ++i) {
            int j = i + len - 1;
            for (int k = i; k < j; ++k) {
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + p[i - 1] * p[j] * p[k]);
            }
        }
    }
    cout << dp[1][n] << endl;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int t = 1;
    while (t--) solve();
    return 0;
}
/*
4
10 100 5 50
*/
posted @ 2021-06-22 21:53  stff577  阅读(61)  评论(0)    收藏  举报