矩阵链乘法—DP

版权声明:看我干嘛? 你又没打算转载我的博客~ https://blog.csdn.net/wjh2622075127/article/details/82533086

矩阵链乘法是这样的问题:

给定n个矩阵:A1,A2,…,An,其中Ai与Ai+1是可乘的,i=1,2…,n-1。确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数。

我们称有如下性质的矩阵乘积链为完全括号化的(fully parenthesized):它是单一矩阵,或者是两个完全括号化的矩阵乘积链的积,且已外加括号。

矩阵乘法是满足结合性的,因此它有许多种计算顺序,我们的目标就是确定计算代价最小的计算顺序。

矩阵链乘法问题和合并石子问题非常相似,所不同的是,合并石子计算的是合并时消耗的体力和,而矩阵链乘法计算的是乘法的次数,因此要进行模型转换时,处理好他们的这点不同就好了。

我的方法是:对于n个矩阵相乘的问题,记录每个矩阵的行数和列数,记录到一个pair<int, int>数组中,后续进行区间dp的时候,维护一个区间的pair<int, int>, 也就是该区间进行矩阵乘法之后生成的矩阵的行数和列数。它的意义在于将一个计算好的区间作为一个矩阵。

#include <iostream>
#include <cstring>
using namespace std;

int main()
{
    int n, dp[10][10], num[10];
    pair<int, int> mat[10][10];
    cin >> n;
    memset(dp, 0x3f, sizeof(dp));
    for (int i = 1; i <= n + 1; ++i) {
        cin >> num[i];
        if (i != n + 1) dp[i][i] = 0;
    }
    for (int i = 1; i <= n; ++i) {
        mat[i][i].first = num[i];
        mat[i][i].second = num[i + 1];
    }
    for (int k = 2; k <= n; ++k) {
        for (int i = 1; i + k - 1 <= n; ++i) {
            int j = i + k - 1;
            for (int l = i; l < j; ++l) {
                int mul = mat[i][l].first * mat[i][l].second * mat[l + 1][j].second;
                if (dp[i][j] > dp[i][l] + dp[l + 1][j] + mul) {
                    dp[i][j] = dp[i][l] + dp[l + 1][j] + mul;
                    mat[i][j].first = mat[i][l].first;
                    mat[i][j].second = mat[l + 1][j].second;
                }
            }
        }
    }
    cout << dp[1][n];
}
/*
2
1 2 3

3
3 4 2 6

6
30 35 15 5 10 20 25  // 15125
*/

猜你喜欢

转载自blog.csdn.net/wjh2622075127/article/details/82533086
今日推荐