矩阵链相乘(动态规划)
创始人
2024-04-12 22:53:43
0

【问题描述】给定n个矩阵M1,M2...MnM_1,M_2...M_nM1​,M2​...Mn​,他们的维数分别是r1∗c1,r2∗c2...rn∗cnr_1*c_1,r_2*c_2...r_n*c_nr1​∗c1​,r2​∗c2​...rn​∗cn​,要求使用【动态规划】的策略求解矩阵连乘的最优计算代价(总乘法次数最少)。题目保证矩阵相乘一定是有效的。

例如有三个矩阵M1,M2,M3M_1,M_2,M_3M1​,M2​,M3​,他们的维度分别是2∗10,10∗2,2∗102*10,10*2,2*102∗10,10∗2,2∗10。按照矩阵乘法的结合律,可以先把M1M_1M1​和M2M_2M2​相乘,然后把结果和M3M_3M3​相乘,总的乘法次数为2∗10∗2+2∗2∗10=802*10*2+2*2*10=802∗10∗2+2∗2∗10=80次;也可以先把M2M_2M2​和M3M_3M3​相乘,再用M1M_1M1​去相乘,这种方式下总的乘法次数为10∗2∗10+2∗10∗10=40010*2*10+2*10*10=40010∗2∗10+2∗10∗10=400次。因此最优计算代价为80。
【输入形式】输入的第1行中有1个数字nnn,表示矩阵的个数;接下来nnn行,每行2个整数rir_iri​和cic_ici​,分别表示矩阵MiM_iMi​的行数和列数。
【输出形式】输出1行中有一个数字,表示nnn个矩阵相乘的最优计算代价。
【样例输入】

3

2 10

10 2

2 10
【样例输出】

80
【说明】

n>=2n>=2n>=2

1<=ri,ci<=201<=r_i,c_i<=201<=ri​,ci​<=20

题解:

我们定义dp[i][j]dp[i][j]dp[i][j]为从第iii个矩阵连乘到第jjj个矩阵的最优代价,那么我们可以得到状态转移方程

∀k∈[i,j),dp[i][j]=dp[i][k]+dp[k+1][j]+r[i]∗c[k]∗c[j]\forall k \in [i,j),dp[i][j]=dp[i][k]+dp[k+1][j]+r[i]*c[k]*c[j]∀k∈[i,j),dp[i][j]=dp[i][k]+dp[k+1][j]+r[i]∗c[k]∗c[j]

解释一下,这个方程的意思就是从第iii号矩阵到第jjj号矩阵的连乘的最优代价等于第iii个矩阵到第kkk个矩阵的最优代价加上第k+1k+1k+1到第jjj个矩阵的最优代价再加上这两边矩阵相乘的代价,其中kkk是大于等于iii且小于jjj的一个正整数。

更通俗地来说,第kkk个矩阵作为第iii号矩阵到第jjj号矩阵的一个分割线,把整条矩阵链分成了两部分,那么总的最优代价就等于左边部分的最优代价加上右边部分的最优代价,再加上把左右两部分拼回去的代价。
请添加图片描述
相当于说,我分割好后,先把左边的矩阵链按照最优的方法计算完得到一个矩阵A,并把代价记下来,再把右边的矩阵链也按照最优的方法计算完得到另一个矩阵B,也把代价记下来,最终,将A与B相乘,这也会产生代价,最后把这三个代价相加,就得到整条矩阵链计算的代价。

但是,不同的kkk会得到不同的代价,因此要在k的取值范围内枚举并计算将每一个kkk作为分割线时,所产生的代价是多少,并取最小值作为整条矩阵链的最优代价。

说了这么多,可能还需要补充一下矩阵相乘的代价需要怎样计算,举例来说,一个1×31\times31×3的矩阵和一个3×53\times53×5的矩阵相乘所产生的计算代价就是1×3×51\times3\times51×3×5;一个1×51\times51×5的矩阵和一个5×55\times55×5的矩阵相乘所产生的计算代价就是1×5×51\times5\times51×5×5。

根据以上举例,可以总结出规律:

一个n1×m1n_1 \times m_1n1​×m1​的矩阵和一个n2×m2n_2 \times m_2n2​×m2​的矩阵相乘所产生的计算代价就是n1×m1×m2n_1 \times m_1 \times m_2n1​×m1​×m2​,当然,众所周知,两个矩阵相乘的必要条件是m1=n2m_1=n_2m1​=n2​,所以把m1m_1m1​替换成n2n_2n2​也是ok的。

其实这个代价仅代表的是两个矩阵相乘所需要使用乘法的次数,我们知道,矩阵相乘不仅需要乘法,也需要加法,但如果单单只是想要比较计算代价来得出最优方法,省略掉加法代价也无伤大雅。

另外,对于一个矩阵链M1×M2×M3×...×MnM_1\times M_2 \times M_3\times...\times M_nM1​×M2​×M3​×...×Mn​来说,它的答案矩阵的规模一定是r1×cnr_1\times c_nr1​×cn​

明确了状态转移方程的意义之后,便需要知道初始状态的情形

  • 由于矩阵本身不需要计算,因此所有的dp[i][i]dp[i][i]dp[i][i]都等于0
  • 考虑矩阵链中只包含两个矩阵的情形,那么dp[1][2]=dp[1][1]+dp[2][2]+r[1]∗r[1]∗c[2]dp[1][2]=dp[1][1]+dp[2][2]+r[1]*r[1]*c[2]dp[1][2]=dp[1][1]+dp[2][2]+r[1]∗r[1]∗c[2]
  • 如果我们画出dpdpdp表可以看到dp[1][1]dp[1][1]dp[1][1]和dp[2][2]dp[2][2]dp[2][2]是位于dp[1][2]dp[1][2]dp[1][2]的左下角的,甚至来说,对于任意一个dp[i][j]dp[i][j]dp[i][j]来说,它的求解都需要用到它左下方的值,如果按照一般的dpdpdp路线,从第一行开始,每一行从第一个开始向右枚举,那么dp[i][j]dp[i][j]dp[i][j]左下方的值根本就没有求解过,何谈根据最优子结构递推得出最优解?

因此,我们dp的路线也有所改变,具体做法代码中已给出,外层循环枚举每一条对角线ddd,第二层循环枚举行号iii,根据行号iii和对角线号ddd可以得出列号t=i+d−1t=i+d-1t=i+d−1,最后一层循环枚举kkk。
在这里插入图片描述

代码:

#include 
using namespace std;
const int inf = 0x3f3f3f3f;
int n, r[21], c[21], dp[21][21];
//def:dp[i][j]代表从第i个矩阵到第j个矩阵的连乘的最优代价void init() {for (int i = 1; i <= n; i++) {dp[i][i] = 0;}
}int main()
{cin >> n;for (int i = 1; i <= n; i++) {cin >> r[i] >> c[i];}init();for (int d = 2; d <= n; d++) {for (int i = 1; i <= n - d + 1; i++) {int t = i + d - 1; dp[i][t] = inf;for (int k = i; k < t; k++) {int cost = dp[i][k] + dp[k + 1][t] + r[i] * c[k] * c[t];if (cost < dp[i][t]) {dp[i][t] = cost;}}}}cout << dp[1][n];
}

相关内容

热门资讯

个人销售住房增值税政策来了 12月29日,财政部、国家税务总局发布“关于个人销售住房增值税政策的公告”。 个人(不含个体工商...
南京拟修订法规加强历史文化名城... 原题:保护利用将设“正负面清单” 《南京市历史文化名城保护条例》将迎大修 南京市历史文化名城保护法规...
《深圳公益诉讼检察工作白皮书(... 深圳新闻网2025年12月31日讯(深圳特区报记者 上官文复 通讯员 李俞青)12月30日,深圳市人...
了解招生政策要选择官方渠道 石向阳 绘 日前,清华大学招生办公室发布声明称,有部分机构与个人冒用学校名义开展招生宣讲,散布不实招...
视频丨日学者:高市言行和政策令... 日本上智大学政治学教授中野晃一近日在接受总台记者采访时指出,高市早苗有关对华立场的言论将进一步破坏日...
10年受理公益诉讼案件线索超8... 深圳特区报讯(记者 上官文复 通讯员 李俞青)12月30日,深圳市人民检察院举办《深圳公益诉讼检察工...
日学者:高市言行和政策令日本面... 日本上智大学政治学教授中野晃一近日在接受总台记者采访时指出,高市早苗有关对华立场的言论将进一步破坏日...
袁家军、胡衡华、刘明胜、徐树彪... 据重庆日报消息,12月30日下午, 国家电投集团水电股份有限公司揭牌。重庆市委书记袁家军,市委副书记...
“3女带4孩续面”被改编成动画... 极目新闻记者 詹钘 近日,有网友发现,郑州续面事件已经被人改编成动画,在短视频平台和短剧平台播放。视...
征兵政策解读之二:征集条件篇 一、年龄条件 1.义务兵。男青年年满18 至22 周岁,普通高等学校本专科毕业生、符合毕业条件的毕业...