虽是读书笔记,可是如转载请注明出处 http://segmentfault.com/blog/exploring/
.. 拒绝伸手复制党算法
如下是算法导论第15章的学习笔记segmentfault
动态规划经常使用于最优化问题。可能存在多个取最优解的值,但愿找到其中一个最优解。函数
[摘自安勃卿的 BLOG][1] 动态规划与分治法相似,也是将问题分解为若干个子问题,先求解子问题,而后从这些子问题的解获得原问题的解。 分治法在问题较大且相互不独立的状况下,因为分解获得的子问题数目太多,各个递归子问题被重复计算屡次,求解过程呈幂级数增加,其时间复杂度为 n 的指数时间。 与分治法不一样,动态规划方法采用自底向上的递推方式求解,而且经分解获得的子问题每每不是相互独立的,根据子问题的相关性,在每步列出可能的局部解中选出能产生最佳解的部分,并将计算过程填表,只要某个子问题被解决, 将不会被屡次计算,从而减小了算法的时间复杂度。 求解问题时每次决策依赖于当前状态,又随即引发状态的转移,决策序列在变化的状态中逐步产生,这种用多阶段最优化决策方式解决问题的过程称为动态规划。 递推关系 (状态转移方程) 是实现由分解后的子问题向最终问题求解转化的纽带。 填表技术是把计算过的全部子问题的解都记录下来,因为将原问题分解后的各个子问题可能存在重复性,因此当之后重复遇到该子问题时,只须要查表继续问题的求解,而不须要重复计算,这样就节省了不少计算时间,这就是动态规划的精髓。
动态规划的设计分为如下四个步骤:学习
动态规划的基本要素(如何判断一个问题能够应用动态规划方法的标志)
1. 一个问题的最优解包含了子问题的一个最优解。优化
动态规划方法的关键在于正确地写出基本的递推关系式和恰当的边界条件。要作到这一点,就必须将原问题分解为几个相互联系的阶段,恰当的选取状态变量和决策变量及定义最优值函数,从而把一个大问题转化成一组同类的子问题,而后逐个求解。即从边界条件开始,逐阶段递推寻优,在每个子问题的求解中,均利用它前面的子问题的最优化结果,依次进行,最后一个子问题所得的最优解就是整个问题的最优解,这样就说明具备最优子结构
当一个递归算法不断地调用同一问题时,则该最优问题包含重叠子问题。 `动态规划`算法老是充分利用重叠子问题,即经过每一个子问题只解一次,把解保存在一个在须要时就能够查看的`表`中。 而`分治法`解决的问题每每在递归的每一步都产生全新的子问题,且对递归树中重复出现的每一个子问题都要重复解一次。
动态规划的时间复杂度:
依赖于两个因素的乘积:1. 子问题的总个数 2. 每一个子问题有多少种选择。
装配线问题一共有O(n)
个子问题,每一个问题2
个选择.故复杂度O^3
矩阵链乘法一共有O(n^2)
个子问题,每一个问题n
个选择.故复杂度O^3
spa
实际问题:
1. 装配线调度 :
寻找最优解结构:
当i=1
时候问题的状况;
当i>1
时候问题的状况;
发现最优子结构能够利用子问题的最优子结构构造原问题的一个最优解。S1,j
与S1,j-1
的关系;或者S2,j-1
的关系。设计
自顶向下再自顶向上的递归方法时间复杂度达到O(2^n)
;而直接从自底向上,能够线性时间解决问题。
2. 矩阵链乘法
问题描述:给定n
个要相乘的矩阵构成的序列链<A1,A2,...,An>
,要计算乘积A1,A2,...,An
可将两个矩阵相乘的标准算法做为一个子程序,根据括号给出的计算顺序作出所有的矩阵乘法。不一样的加所有括号顺序所带来的矩阵乘法的代价不一样。
好比:(A1,(A2(A3,A4)))
...
(A1(A2A3)A4)
code
因此矩阵链乘法问题其实是,要求获得一种最小化标量乘法次数的方式进行加所有括号。即肯定具备最小代价的矩阵相乘顺序。该问题的最优子结构以下:假设 A1 A2...An
的一个最优加括号把乘积在 Ak
和 Ak+1
间分开,则前缀子链 A1...Ak
的加括号方式一定为 A1...Ak
的一个最优加括号,后缀子链同理。blog
设矩阵Ai
的维数pi-1 * pi
递归
使用自底向上的表格法来计算最优代价。
先贴一段这块用到的两个矩阵相乘的代码:
//矩阵相乘 public class MatrixMultiply { // 矩阵的乘法 public int[][] martirxMultiply(int A[][], int B[][]){ int result [][] = new int [A.length][B[0].length]; if(A[0].length != B.length){ System.out.println("test"); return result; } else{ // result 的每一行 for(int i=0;i<A.length;i++) // result 的每一列 for(int j=0;j<B[0].length;j++) // 对每一个元素的计算 for(int k = 0;k<A[0].length;k++) result[i][j] = result[i][j] + A[i][k]*B[k][j]; } return result; } public static void main(String[] args) { MatrixMultiply m = new MatrixMultiply(); int[][] a={{1,2},{3,4},{5,6}};// 本身定义矩阵 int[][] b={{1,2,3},{4,5,6}}; int [][] result = m.martirxMultiply(a, b); for(int i=0;i<a.length;i++) for(int j=0;j<b[0].length;j++) System.out.println(result[i][j]); } }