首页 > 其他分享 >dp-矩阵链相乘顺序

dp-矩阵链相乘顺序

时间:2023-08-13 16:47:40浏览次数:33  
标签:mat int mount 矩阵 A1 相乘 dp

矩阵链相乘顺序

目录

问题描述

A1,A2,..,An 表示n个矩阵的序列,其中Ai为\(P_{i−1}×P_i\)阶矩阵,i=1,2,...,n。
向量P=<P0,P1,P2..Pi>表示矩阵链的输入,其中P0是A1的行数,P1是A1的列数,P1是A2的行数,以此类推。
计算这个矩阵需要做n−1次两个矩阵的相乘运算,可以用n−1对括号表示运算次序。
因为矩阵乘法满足结合律,所以无论采用那种顺序,最后结果都一样,但是采用不同的顺序计算的工作量不同。如何定义两个矩阵相乘的工作量呢?
所以假设A1有i行k列,A2有k行j列。所以A1A2相乘后的矩阵有i行j列,含ij个元素。
以元素相乘作为基本运算,乘积中每个元素的计算都需要做j次乘法,于是计算A1A2总共需要ijk次乘法。

举例说明

假设输入的是P=<10,100,5,50>,说明有3个矩阵相乘。其中,
A1:10×100
A2:100×50
A3:5×50

有两种乘法次序:
(A1A2)A3
A1(A2A3)

执行第一种运算的基本运算次序:10×100×5+10×5×50=7500
执行第二种运算的基本运算次序:10×100×50+100×5×50=75000
工作量相差达10倍!
所以我们的问题是:给定向量P,确定一种乘法次序,使得基本运算的总次数最少。

问题分析

1、寻找最优子结构:
假设我们已经找到父矩阵链最优解,当我们划分到最后一步时都是两个子矩阵链(分别被括号包围)相乘,如(A1A2A3A4)(A5A6A7),此时显然外括号为父矩阵的最优括号划分。继续往下划分,((A1A2A3)A4)(A5(A6A7)),则两个子矩阵链的划分括号必须也为他们本身的最优括号划分。因为如果子矩阵链的划分括号不是他们本身的最优括号划分时,两个子矩阵链就有另一种最优括号划分,如(A1(A2A3A4))(A5(A6A7))。那么就与我们的假设相悖。((A1A2A3)A4)(A5(A6A7))不是我们父矩阵最优解。所以拥有最优划分的父矩阵的子矩阵链显然也拥有最优划分。

2、子问题重叠:
在分解子结构的过程中,会多次访问同一个子问题,比如 (A1(A2A3A4))(A5(A6A7)) 和 (A1(A2A3A4)A5)(A6A7)。
这正是动态规划解决的问题。

程序

#include <iostream>
#include <vector>
#include <new>
#include <climits>

using namespace std;

int solve(const vector<pair<int, int>>& mat_chain);
void print_mat(int** mat, int len1, int len2);


int main (int argc, char** argv) {
    vector<pair<int, int>> mat_chain{
        {10,100},
        {100,5},
        {5,50},
        {50,9},
    };

    int ret = solve(mat_chain);
    cout << "ret: " << ret << endl;

    return 0;
}

int solve(const vector<pair<int, int>>& mat_chain) {
    int len = mat_chain.size();
    int i, j, k, diff, sum;
    int** order = new int*[len];
    // mount 右上存放计算量:[i,j]矩阵链的最小计算量为mount[i,j]
    // mount 左下存放计算顺序:mount[i][j]=k 表示[i,j]矩阵链分割为[i,k]和[k+1,j]两部分
    //   先分别计算这两部分,再对其相乘
    int** mount = new int*[len];
    for (i = 0; i < len; ++i) {
        mount[i] = new int[len];
        for (j = 0; j < len; ++j) {
            mount[i][j] = INT_MAX;
        }
        // 对角线表示自己和自己相乘,计算量为0
        mount[i][i] = 0;
    }

    for (diff = 1; diff < len; ++diff) {
        for (i = 0; i < len - diff; ++i) {
            j = i + diff;
            for (k = i; k < j; ++k) {
                // 计算量=分割的两部分各自的计算量加上两部分相乘的计算量
                sum = mount[i][k] + mount[k+1][j]
                    + mat_chain[i].first * mat_chain[k].second * mat_chain[j].second;
                if (sum < mount[i][j]) {
                    mount[i][j] = sum;
                    mount[j][i] = k;
                }
            }
        }
    }
    cout << "mount:\n";
    print_mat(mount, len, len);
    sum = mount[0][len-1];

    for (i = 0; i < len; ++i) {
        delete[] mount[i];
    }
    delete[] mount;

    return sum;
}

void print_mat(int** mat, int len1, int len2) {
    for (int i = 0; i < len1; ++i) {
        for (int j = 0; j < len2; ++j) {
            cout << mat[i][j] << "\t";
        }
        cout << endl;
    }
}

测试:

mount:
0	5000	7500	7700
0	0	25000	6750
1	1	0	2250
1	1	2	0
ret: 7700

标签:mat,int,mount,矩阵,A1,相乘,dp
From: https://www.cnblogs.com/minding/p/17626753.html

相关文章

  • dp-钢条切割
    钢条切割目录钢条切割问题描述问题分析思路及简化自顶向下递归带备忘录的递归自底向上程序问题描述Serling公司购买长钢条,将其切割为短钢条出售。假设切割工序没有成本,不同长度的钢条的售价如下:length12345678910price1589101717202430那么钢......
  • dp-摸牌博弈
    摸牌博弈//摸牌博弈//一维排列的卡牌,其上有不同的数字,两个对手A和B依次从中摸牌//卡牌及顺序均对两人可见//每次只能从最左或最右摸牌//最终摸到的卡牌数字之和最大者获胜//两个人都绝顶聪明(两人都会选择对自己有利对对手不利的牌)#include<iostream>#include<n......
  • dp-最长回文子序列
    最长回文子序列算法导论3rd-15.2问题描述回文:palindrome,是正序和逆序完全相同的非空字符串一个字符串有许多子序列,可以通过删除某些字符而变成回文字符串,字符串“cabbeaf”,删掉‘c’、'e'、‘f’后剩下的子串“abba”就是回文字符串,也是其中最长的回文子序列。在一个给定的......
  • dp-最长公共子序列
    最长公共子序列目录最长公共子序列问题描述最长公共子序列不等于最长公共子串问题分析程序问题描述最长公共子序列(LCS)是一个在一个序列集合中(通常为两个序列)用来查找所有序列中最长子序列的问题。一个数列,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的......
  • dp-最优二叉搜索树
    最优二叉搜索树目录最优二叉搜索树问题描述问题分析思路程序问题描述最优二叉搜索树(OptimalBinarySearchTree,OptimalBST)问题,形式化定义:给定一个n个不同关键字的已排序的序列K=<k1,k2,...,kn>(k1<k2<...<kn),用这些关键字构造一棵二叉搜索树——对每个关键字ki,都有一个概......
  • 无涯教程-Perl - readpipe函数
    描述该函数将EXPR作为命令执行。然后,将输出作为标量文本中的多行字符串返回,或者将行作为列表context中的单个元素返回。语法以下是此函数的简单语法-readpipeEXPR返回值此函数在标量context中返回String,在列表context中返回List。例以下是显示其基本用法的示例代码......
  • 复习:矩阵快速幂
    前言emmm太久了忘了许多写笔记来复习一下概念矩阵乘法什么是矩阵乘法?给你两个矩阵\(a,b\)则令\(c=a*b\)有\(c_n=a_n\),\(c_m=b_m\)\[\sum\limits_{i=1}^{c_n}\sum\limits_{j=1}^{c_m}c_{i,j}\sum\limits_{k=1}^{a_m}a_{i,k}*b_{k,j}\]两个矩阵做乘法的前提:\(a_m=b_n\)......
  • 斜率优化DP
    前置芝士单调队列优化DP⌈写不动数据结构呜呜呜,先来补这个⌋对于一个DP,我们想优化祂的⌈转移⌋有些题目的可选状态有以下特征需要寻找最值可选状态区间平移存在可以永久去除的多余状态感性的讲,可行性是一个滑动窗口,状态两两之间都可以⌈直接比较出优劣......
  • UDP
    UDP不像TCP创建连接时有3次握手,而是直接发送数据,不管对方是否接收到。UDP网络通信不区分客户端和服务端。 UDP收发数据的步骤1.创建UDP套接字对象2.直接发送数据3.读取数据4.关闭套接字 示例服务端1'''2UDP应该说没有服务端和客户端,只是习惯称发......
  • 1572. 矩阵对角线元素的和
    1572.矩阵对角线元素的和2023年8月12日19:07:511572.矩阵对角线元素的和简单给你一个正方形矩阵mat,请你返回矩阵对角线元素的和。请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。示例1:输入:mat=[[1,2,3],[4,5,6],[......