`
shuofenglxy
  • 浏览: 194463 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

矩阵链乘法算法讲解

阅读更多

矩阵链乘是一个计算性问题,是动态规划的适用范例。

动态规划要满足以下三个条件:

1 最优化原理(最优子结构性质)

最优化原理可这样阐述:一个最优化策略具有这样的性质,不论过去状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。简而言之,一个最优化策略的子策略总是最优的。一个问题满足最优化原理又称其具有最优子结构性质

 

2.无后向性

将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态无法直接影响它未来的决策,而只能通过当前的这个状态。换句话说,每个状态都是过去历史的一个完整总结。这就是无后向性 ,又称为无后效性

如果用前面的记号来描述无后向性,就是:对于确定的xk ,无论p1,k-1 如何,最优子策略pkn* 是唯一确定的,这种性质称为无后向性。

 

3.子问题的重叠性

动态规划将原来具有指数级复杂度的搜索算法改进成了具有多项式时间的算法。其中的关键在于解决冗余 ,这是动态规划算法的根本目的。动态规划实质上是一种以空间换时间的技术,它在实现的过程中,不得不存储产生过程中的各种状态,所以它的空间复杂度要大于其它的算法。

 

具体矩阵链乘分析:

 矩阵乘法有这样的特点: A(m,n),B(n,q)两个矩阵相乘产生一个C(m,q),总的计算次数为m*n*q。而且,矩阵链中,任何两个连续矩阵提前相乘对产生的最终结果没有影响,只是对产生的运算次数有影响。所以,基于这点,通过估算运算次数,可以选出运算次数最少的方案进行矩阵乘法运算,节约运算次数。

 

具体思路参见代码及注释:

矩阵类:

package matrixchain;

import java.util.Random;

public class Matrix {

	private int m;//矩阵行
	
	private int n;//矩阵列
	
	private double [][] matrix ;//存放矩阵元素
	private  static int count=0;//统计一次运算中调用的乘法运算次数
	
	public static int getCount() {
		return count;
	}

	public static void setCount(int count) {
		Matrix.count = count;
	}

	public  Matrix(int m,int n){
		this.setM(m);
		this.setN(n);
		setMatrix(new double[m][n]);
		
	}
	
	public  static  Matrix mutiplyMatrix(Matrix A,Matrix B){
		if(A.getN()!=B.getM()){
			System.out.println("不合矩阵相乘条件");
			System.exit(0);
		}
		Matrix result = new Matrix(A.getM(),B.getN());
		for(int i = 0;i<result.getM();i++)
			for(int j = 0;j<result.getN();j++){
				double temp=0;
				for(int p = 0;p<A.getN();p++){
					temp += A.getMatrix()[i][p]*B.getMatrix()[p][j];
					count++;
					}
				result.getMatrix()[i][j] = temp;
			}
		return result;
	}

	public static Matrix generateElement(Matrix input){
		Random random = new Random(47);
		for(int i = 0;i<input.getM();i++)
			for(int j = 0;j<input.getN();j++)
				input.getMatrix()[i][j] = random.nextDouble()*1000;
		
		return input;
	}
	public void setM(int m) {
		this.m = m;
	}

	public int getM() {
		return m;
	}

	public void setN(int n) {
		this.n = n;
	}

	public int getN() {
		return n;
	}

	public void setMatrix(double[][] matrix) {
		this.matrix = matrix;
	}

	public double [][] getMatrix() {
		return matrix;
	}
}
 
矩阵链类:
package matrixchain;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class MatrixChain {
	/**
	 * 存放矩阵
	 */
	private List<Matrix> matrixChain;
	
	/**
	 * 存放矩阵子链计算次数
	 */
	private  double[][] m;
	/**
	 * 存放子链最优划分位置
	 */
	private int[][] s;
	
	private static int[] sizeLimit;
	
	
	public MatrixChain(int[] sizeLimit){
		int n = sizeLimit.length-1;
		this.setMatrixChain(generateMatrixChain(sizeLimit));
		this.setM(new double[n][n]);
		this.setS(new int[n][n]);
	}
	
	/**
	 * 生成矩阵链
	 * @param sizeLimit 这是矩阵的行列数组 根据接着的两个元素表示一个矩阵的行与列 
	 * 矩阵链为如下形式:A0A1.....An-1
	 * @return
	 */
	private static  List<Matrix> generateMatrixChain(int[] sizeLimit){
		List<Matrix> resultChain = new ArrayList<Matrix>();
		for(int i =0;i<sizeLimit.length-1;i++){
			Matrix temp = new Matrix(sizeLimit[i],sizeLimit[i+1]);
			Matrix.generateElement(temp);
			resultChain.add(temp);
		} 
		return resultChain;
	}
	/**
	 * 生成numbs个整数表示n-1个矩阵的行与列大小
	 * 此处的15 并没有特殊含义,只是为了保证数组中元素值大小都不为0
	 * @param nums
	 */
	public static int[] generateMatrixDetails(int nums){
		Random random = new Random(47);
		sizeLimit = new int[nums];
		for(int i=0;i<nums;i++){
				sizeLimit[i]= (int)random.nextInt(nums);
			}
		return sizeLimit;
	}
	/**
	 * 普通 的矩阵链直接顺序乘法
	 * @param matrixChain
	 * @return
	 */
	public Matrix mutiplyMatrixChain(List<Matrix> matrixChain){
		checkMatrixChain(matrixChain);
		
		Matrix result =null;
		for(int i=0;i<matrixChain.size()-1;i++){
			if(i==0)
				result = Matrix.mutiplyMatrix(matrixChain.get(0), matrixChain.get(1));
			else
				result = Matrix.mutiplyMatrix(result, matrixChain.get(i+1));
		}
		return result;
	}
	/**
	 * 优化的矩阵链乘
	 * @param matrixChain
	 * @return
	 */
	public Matrix optimizedMutiplyMatixChain(List<Matrix> matrixChain){
		checkMatrixChain(matrixChain);
		
		Matrix result =null;
		long start = System.nanoTime();
		calMinMutiplyTimes(matrixChain,sizeLimit);
		long end = System.nanoTime();
		System.out.println("OptimizedMutiplyMatixChain Method calculate postion totally costs  "+(end-start)+"  nanoseconds");
		result = mutiplyMatrixChainOptimized(matrixChain,s,0,matrixChain.size()-1);
		return result;
	}
	
	 private Matrix mutiplyMatrixChainOptimized(List<Matrix> matrixChain,int[][]s,int i,int j){

         Matrix x,y;

         if (j>i){

                x=mutiplyMatrixChainOptimized(matrixChain,s,i,s[i][j]);

                y=mutiplyMatrixChainOptimized(matrixChain,s,s[i][j]+1,j);

                return Matrix.mutiplyMatrix(x, y);
                

         }

        return matrixChain.get(i); 

  }
	private void initMArray(){
		for(int i =0;i<m.length;i++)
			m[i][i] = 0;
		
		for(int i=0;i<m.length;i++)
			for(int j =i+1;j<m.length;j++)
				m[i][j] = 999999999999999999999.0;
	}
	
	private void initSArray(){
		for(int i=0;i<m.length;i++)
				s[i][i] = 0;
	}
	
	/**
	 * 计算最小乘法次数,将子链最小次数放在m数组中,将加括号位置放在s数组中
	 * @param matrixChain
	 * @param sizeLimit
	 * 算法思想:
	 * 1 计算出m[p][q]的起始值并将括号位置放在p位置
	 * 2在p q之间取出括号位置,计算出比原值小的m[p][q]值替换掉原值,并替换掉括号位置
	 */
	
	private void calMinMutiplyTimes(List<Matrix> matrixChain, int[] sizeLimit) {

		initMArray();
		initSArray();

		int n = matrixChain.size();
		for (int l = 2; l < n; l++) {

			for (int i = 1; i < (n - l + 1); i++) {

				int j = i + l - 1;

				for (int k = i; k < j; k++) {

					double q = m[i][k] + m[k + 1][j] + sizeLimit[i - 1]
							* sizeLimit[k] * sizeLimit[j];

					if (q < m[i][j]) {

						m[i][j] = q;

						s[i][j] = k;

					}

				}

			}

		}

	}
	
	/**
	 * 校验输入的矩阵链是否符合乘法运算条件
	 * @param matrixChain
	 */
	private void checkMatrixChain(List<Matrix> matrixChain){
		if(matrixChain.size()<2){
			System.out.println("矩阵个数小于2,不能做乘法");
			System.exit(0);
		}
	}
	
	
	public void setM(double[][] m) {
		this.m = m;
	}
	public double[][] getM() {
		return m;
	}
	public void setS(int[][] s) {
		this.s = s;
	}
	public int[][] getS() {
		return s;
	}
	public void setMatrixChain(List<Matrix> matrixChain) {
		this.matrixChain = matrixChain;
	}
	public List<Matrix> getMatrixChain() {
		return matrixChain;
	}
	
	public int[] getSizeLimit(){
		return MatrixChain.sizeLimit;
	}
}
 
测试类:
package matrixchain;
/**
 * 
 * @author shuofenglxy
 */
public class MatrixChainMuitiplyTest {

	
	public static void main(String[]args){
		
		MatrixChain demo = new MatrixChain(MatrixChain.generateMatrixDetails(200));
		
		
		/**优化的的矩阵链取最佳加括号位置相乘
		 * 统计消耗时间和共计的加法次数
		 */
		long startNomal = System.nanoTime();
		demo.optimizedMutiplyMatixChain(demo.getMatrixChain());
		long endNomal = System.nanoTime();
		System.out.println("OptimizedMutiplyMatixChain Method totally costs  "+(endNomal-startNomal)+"  nanoseconds");
		System.out.println("OptimizedMutiplyMatixChain Method caluclating times is: "+Matrix.getCount()+" times");
		
		//将统计运算次数总数归0
		Matrix.setCount(0);
		
		System.out.println("---------------------");
		
		/**正常的矩阵链直接相乘
		 * 统计消耗时间和共计的加法次数
		 */
		startNomal = System.nanoTime();
		demo.mutiplyMatrixChain(demo.getMatrixChain());
		endNomal = System.nanoTime();
		System.out.println("NomalMethod totally costs  "+(endNomal-startNomal)+"  nanoseconds");
		System.out.println("NomalMethod caluclating times is: "+Matrix.getCount()+" times");
	}
}
 

测试结果:

OptimizedMutiplyMatixChain Method calculate postion totally costs  19624306  nanoseconds
OptimizedMutiplyMatixChain Method totally costs  385362418  nanoseconds
OptimizedMutiplyMatixChain Method caluclating times is: 52070102 times
---------------------
NomalMethod totally costs  768270995  nanoseconds
NomalMethod caluclating times is: 111755908 times

 

结果分析:

可以看到,通过提前计算好加括号位置,虽然耗费一定的时间,但大大减少的运算次数,从而节省了矩阵链乘的总时间,这里相比原来的直接相乘,空间代价增加,但时间代价减少,也是经典的空间换时间思路。

参考资料:

http://hi.baidu.com/lewutian/blog/item/f46bf609b7c55ec53ac7633c.html

算法导论相关章节

 

1
1
分享到:
评论

相关推荐

    算法-矩阵乘法(信息学奥赛一本通-T1125)(包含源程序).rar

    5. 动态规划和矩阵链乘法:在某些问题中,矩阵乘法可以用来优化动态规划的状态转移。 总的来说,"算法-矩阵乘法(信息学奥赛一本通-T1125)(包含源程序).rar"资源为学习者提供了一个全面的学习平台,不仅有理论...

    HDU算法讲解的PPT

    3. **动态规划**:这是解决最优化问题的重要方法,例如背包问题、最长公共子序列、矩阵链乘法等。动态规划强调状态转移方程和最优子结构,理解这些原理有助于解决各种复杂问题。 4. **字符串算法**:如KMP匹配、...

    C语言-常用经典算法及讲解

    5. **动态规划**:解决最优化问题的利器,如背包问题、最长公共子序列、矩阵链乘法等。动态规划的关键在于状态转移方程和边界条件的设计。 6. **字符串处理**:C语言中的字符串操作涉及到字符串长度计算、字符串...

    稀疏矩阵的十字链表表示方法:矩阵加减乘法运算、矩阵转置运算、矩阵项的插入、矩阵行列链表的排序

    本文将详细讲解使用C语言实现稀疏矩阵的十字链表表示方法,以及相关的矩阵运算,包括矩阵加减乘法、矩阵转置和矩阵项的插入,以及对矩阵行列链表的排序。 1. **稀疏矩阵的概念**: - 稀疏矩阵是指大部分元素为零的...

    矩阵及其基本算法PPT学习教案.pptx

    在稀疏矩阵中,乘法可能涉及大量元素的合并和更新,优化算法至关重要。 在选择矩阵表示方法时,应根据实际需求考虑适用范围、空间效率、操作时间复杂度和实现难度。每种方法都有其优点和局限性,需要根据具体应用...

    软件设计师动态规划-矩阵链相乘.ppt

    软件设计师考试算法分析与设计动态规划矩阵详细讲解

    《计算机算法设计与分析》算法实现题2-1

    4. **动态规划**:动态规划是一种解决最优化问题的方法,如背包问题、最长公共子序列、矩阵链乘法等。它的核心思想是将问题分解为子问题,并存储子问题的解,避免重复计算,从而达到优化的效果。 5. **递归与分治...

    算法导论试题及答案

    4. **动态规划**:了解基本的动态规划思想,如背包问题、最长公共子序列、矩阵链乘法等问题的解决。 5. **数据结构**:数组、链表、栈、队列、哈希表、树(二叉树、平衡树如AVL和红黑树)、图等,以及它们在算法...

    算法心得 高效算法的奥秘原书第2版) .zip

    书中详细阐述了动态规划的基本思想,以及如何使用它来解决背包问题、最长公共子序列、矩阵链乘法等问题。 此外,书中还讨论了贪心算法、回溯法、分支限界法等高级算法技术,以及如何使用这些方法解决实际问题。这些...

    (陈慧南 第3版)算法设计与分析——课后习题答案(1~8章)

    本章讲解了背包问题、最长公共子序列、矩阵链乘法等问题的动态规划解法。 7. **第七章:贪心算法** 贪心算法在每次决策时都采取当前看起来最好的选择,期望达到全局最优。这一章会介绍贪心策略在求解活动安排、...

    算法导论 MIT 英文版原版

    动态规划是算法设计的一个重要方法,书中通过背包问题、最长公共子序列、矩阵链乘法等经典实例,让读者掌握如何运用动态规划解决复杂问题。此外,书中还介绍了分治策略、回溯法和贪心算法等重要的算法设计技巧。 ...

    算法导论章节答案(16~20章)

    本章主要介绍了基本的动态规划思想,如最优子结构和重叠子问题,并通过背包问题、矩阵链乘法、最长公共子序列等经典例子进行阐述。理解动态规划的状态转移方程是掌握这一章的关键。 第18章:贪心算法 贪心算法是另...

    ACM超级经典算法大集合

    动态规划是解决复杂问题的有效工具,如背包问题、矩阵链乘法、最长公共子序列等,通过构建状态转移方程,可以优化时间复杂度。 数学算法不容忽视,包括数论(质因数分解、模运算、最大公约数和最小公倍数)、组合...

    动态规划动态规划动态规划

    此外,动态规划还常常被用于解决其他类型的问题,例如背包问题、最长公共子序列、最短路径问题(如Floyd-Warshall算法)、矩阵链乘法等。在矩阵链乘法的例子中,动态规划同样用于优化计算顺序,减少计算次数。 总之...

    哈工大 算法设计与分析课件

    4. **动态规划**:背包问题、最长公共子序列、最短路径问题、矩阵链乘法等经典实例。 5. **贪心算法**:解决局部最优解能导致全局最优解的问题,如霍夫曼编码、Prim算法构建最小生成树。 6. **回溯法与分支限界法*...

    算法艺术与信息学竞赛课件(刘汝佳,黄亮)

    2. **动态规划**:讲解如何运用动态规划解决复杂问题,如背包问题、最长公共子序列、矩阵链乘法等,强调状态转移方程的设计。 3. **贪心算法**:介绍如何通过局部最优选择来达到全局最优解,例如霍夫曼编码、活动...

    算法笔记.胡凡

    动态规划是解决许多复杂问题的有效工具,书中会涵盖基本的动态规划思想,如背包问题、最长公共子序列、矩阵链乘法等典型问题的求解方法。 最后,可能会涉及一些高级算法,比如贪心算法、回溯法、随机化算法等,这些...

    Algorithms.算法概论中文版

    动态规划是一种强大的技术,用于解决具有重叠子问题和最优子结构的问题,如背包问题、最长公共子序列和矩阵链乘法。通过记忆化搜索,动态规划可以避免重复计算,从而提高效率。 贪心算法和分治策略是另一种解决问题...

    MIT 2018年算法课件

    动态规划是一种强大的解决问题的方法,课件会深入探讨背包问题、最长公共子序列、矩阵链乘法等经典问题,通过实例帮助学生理解如何构造状态转移方程和最优子结构。 五、贪心算法 贪心算法是另一种有效的策略,它在...

    算法导论-国外权威教材

    此外,书中还探讨了算法在特定问题上的应用,如线性时间排序、矩阵链乘法、最短路径问题和活动选择问题等。书中对这些问题的解决方案不仅展示了算法的强大功能,还展现了作者对算法应用深度的把握。 更进一步,...

Global site tag (gtag.js) - Google Analytics