文章目录
前言
这篇文章是我的实验报告的一部分,其中包含了我很多的理解,希望可以帮助学习该部分的同学。由于还是学生,并且第一次学习,如有错误请多包含。
这篇文章由于作者很懒,很多地方之间照搬了本人的实验报告,公式多的地方使用了截图的形式,也有很多冗余的内容,如果未来有时间,可能会重新写一篇格式工整,内容精炼的动态算法的内容吧…如果对该文章不满,请一定要包容。
觉得前面太繁琐,可以直接跳到最后看代码!!!!!
一、实现矩阵连乘的动态规划算法
数学知识简述:p行q列矩阵与q行r列矩阵相乘得到p行r列矩阵,矩阵相乘需要满足第一个矩阵的列数等于第二个矩阵的行数,得到的矩阵中每个元素由第一个矩阵对应行的每个元素与第二个矩阵中对应列的每个元素依次相乘再相加,由此可得矩阵乘法的时间复杂度为Θ(p q r)。由于矩阵满足乘法结合律,我们可以先使用括号明确其计算顺序,任何加括号的方法最终都可以得到相同的结果,但是不同计算顺序却对乘积运算的代价产生巨大的影响,所以我们要用较少的代价找到其计算矩阵乘积所需标量乘法次数最少的结果以便简化运算。所以要找到一个最优的完全括号化的矩阵乘积链就成为了这部分的目标。(下表是我制作的一个方便理解的矩阵乘积的图解)。
1. 解动态规划第一步—-问题结构分析(最优括号化方案的结构特征)(分解最优解的结构)
我们首先寻找最优子结构,然后就可以利用这种子结构从子问题的最优解构造出原问题的最优解。结构分析简单来说,就是要计算下标i到j的矩阵的乘积的最优解,就是找到一个整数k,由其划分的前半部分和后半部分相乘,得到的乘法次数最少。当然前\后半部分也要是最优的,然后利用最优的前\后部分合成整体的最优解。最优子结构性质是该问题能用动态规划求解的最重要的特征。
2. 解动态规划第二步—-递归关系建立(一个递归求解方案)
这个过程是用子问题的最优解来定义原问题,简单来说就是第一步的延申,假设我们找到最优括号分割点在k,原问题的最少代价是下标i到k的代价加上k+1到j的代价再加上这两个矩阵的运算次数。但是我们不知道k的值,只知道k有j-i种可能,所以只需要查找所有可能即可。还需要注意,我们找到了最优代价,但是它并没有提供足够的信息来构造最优解,为此我们还需要保存最优括号化分割点。下面是一些符号上的定义。
3. 解动态规划第三步—-自底向上计算(计算最优代价)
这一步我打算从伪代码与一些图解开始。
在自底向上的这一部分,如果用文字描述该过程,我想我能写很多很多,但是我认为,我在学习动态规划的过程中的思想都集中到了上面的图中,下面我主要分析一下运行时间与数据结构。
4. 解动态规划第四步—-最优方案追踪(构造最优解)
虽然前面的步骤求出了计算矩阵链乘积所需的最少标量乘法运算次数,但它并未直接给出如何进行这种最优代价的矩阵链乘法运算。我们在主程序中定义了辅助构造最优解的2重向量,现在我们可以通过我们的记录递归的求出更早的矩阵乘法的具体计算过程,也就是最优方案追踪。该过程的思路很容易理解,下面给出伪代码。(与书上的代码思路类似,但是个人感觉这样的实现更容易理解,一看就懂,先打印括号)
5. 代码实现
本次代码参照伪代码,在没有任何参考的情况下编写的,由于最近在看很多写代码的书,故尝试了使用有意义的变量名,但是可能由于变量名过长,导致效果并不好。其次我认为,认真做一个任务并自主实现比潦草的完成多个任务更好,所以这次集中认真的做好这个任务,但是其它任务也要做。
二、 最长公共子序列
这一部分,几乎所有讲述动态规划的资料都会提到,因此对其理解也是所有任务中最透彻的,但是由于本次实验选择的重心是任务二,所以该部分我打算多放一些理解上的内容,和更多的图(图形化的学习算法是更容易的)。注:python课曾流过一次作业,当时想了很久,用了三个方法(两个都是暴力破解,而且对动态规划也步理解),有个方法写了100多行的代码才实现了该功能,如今再看,茅塞顿开。
尝试从另一个角度想,动态解决方案都涉及网络,单元格中的值通常是要优化的值,每个单元格都是一个子问题,所以就要考虑要如何将问题划分为子问题?网格的坐标是什么?现在我考虑费曼算法(Feynman algorithm),写下问题,好好思考,写下答案。我尝试画了一些图表找公共子序列。
图解(引入)
引入部分通常不能满足实际需求,比如fosh是与fish更像还是与fort更像?我们需要更新我们的方法去解决这个问题。
当然,递推关系与伪代码还有时间复杂度还是要给出来:
三、电路布线
思路:该问题与背包问题相似。作为动态规划的问题,求解专注于表格,对于问题的分析大致为每次减小问题的规模,方式是每次少考虑一个上端接线柱。该问题也是要填表格(动态规划问题)。表格的思想是从底向上的解决