矩阵连乘实验报告

合集下载

矩阵的乘法实验报告

矩阵的乘法实验报告

一、实验目的1. 理解矩阵乘法的概念和运算规则。

2. 掌握矩阵乘法的编程实现方法。

3. 通过实验验证矩阵乘法的正确性。

二、实验环境1. 操作系统:Windows 102. 编程语言:Python3. 库:NumPy三、实验原理矩阵乘法是指两个矩阵相乘的运算。

设矩阵A为m×n的矩阵,矩阵B为n×p的矩阵,则它们的乘积C为一个m×p的矩阵。

矩阵乘法的运算规则如下:C[i][j] = Σ(A[i][k] B[k][j]),其中k为1到n的整数。

四、实验步骤1. 导入NumPy库。

```pythonimport numpy as np```2. 定义矩阵A和B。

```pythonA = np.array([[1, 2], [3, 4]])B = np.array([[5, 6], [7, 8]])```3. 计算矩阵A和B的乘积C。

```pythonC = np.dot(A, B)```4. 打印结果。

```pythonprint("矩阵A:")print(A)print("矩阵B:")print(B)print("矩阵C(A乘B):")print(C)```五、实验结果与分析1. 运行实验程序,得到以下结果:```矩阵A:[[1 2][3 4]]矩阵B:[[5 6][7 8]]矩阵C(A乘B):[[19 22][43 50]]```2. 分析结果:- 矩阵A为2×2的矩阵,矩阵B为2×2的矩阵,它们的乘积C为2×2的矩阵。

- 根据矩阵乘法的运算规则,我们可以计算出矩阵C的每个元素。

- 实验结果与理论计算相符,说明矩阵乘法的编程实现是正确的。

六、实验总结1. 本实验成功实现了矩阵乘法的编程,验证了矩阵乘法的正确性。

2. 通过实验,加深了对矩阵乘法概念和运算规则的理解。

3. NumPy库在矩阵运算方面具有强大的功能,为编程提供了便利。

矩阵连乘算法

矩阵连乘算法

福州大学数学与计算机科学学院《计算机算法设计与分析》上机实验报告(2)i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。

由于在计算是并不知道断开点k 的位置,所以k还未定。

不过k的位置只有j-i个可能。

因此,k是这j-i个位置使计算量达到最小的那个位置。

综上,有递推关系如下:若将对应m[i][j]的断开位置k记为s[i][j],在计算出最优值m[i][j]后,可递归地由s[i][j]构造出相应的最优解。

s[i][j]中的数表明,计算矩阵链A[i:j]的最佳方式应在矩阵Ak和Ak+1之间断开,即最优的加括号方式应为(A[i:k])(A[k+1:j)。

从s[1][n]记录的信息可知计算A[1:n]的最优加括号方式为(A[1:s[1][n]])(A[s[1][n]+1:n]),进一步递推,A[1:s[1][n]]的最优加括号方式为(A[1:s[1][s[1][n]]])(A[s[1][s[1][n]]+1:s[1][s[1][n]]])。

同理可以确定A[s[1][n]+1:n]的最优加括号方式在s[s[1][n]+1][n]处断开...照此递推下去,最终可以确定A[1:n]的最优完全加括号方式,及构造出问题的一个最优解。

3、动态规划迭代算法设计:用动态规划迭代方式解决此问题,可依据其递归式自底向上的方式进行计算。

在计算过程中,保存已解决的子问题的答案。

每个子问题只计算一次,而在后面需要时只需简单检查一下,从而避免了大量的重复计算,最终得到多项式时间的算法。

4、算法代码:1. //3d1-2 矩阵连乘动态规划迭代实现2. //A1 30*35 A2 35*15 A3 15*5 A4 5*10 A5 10*20 A6 20*253. //p[0-6]={30,35,15,5,10,20,25}4. #include "stdafx.h"5. #include <iostream>6. using namespace std;7.8. const int L = 7;9.10. int MatrixChain(int n,int **m,int **s,int *p); 11. void Traceback(int i,int j,int **s);//构造最优解 12.13. int main()14. {15. int p[L]={30,35,15,5,10,20,25};16.17. int **s = new int *[L];18. int **m = new int *[L];19. for(int i=0;i<L;i++)20. {21. s[i] = new int[L];22. m[i] = new int[L];23. }24.25. cout<<"矩阵的最少计算次数为:"<<MatrixChain(6,m,s,p)<<endl;26. cout<<"矩阵最优计算次序为:"<<endl;27. Traceback(1,6,s);28. return 0;29. }30.31. int MatrixChain(int n,int **m,int **s,int *p) 32. {33. for(int i=1; i<=n; i++)34. {35. m[i][i] = 0;36. }37. for(int r=2; r<=n; r++) //r为当前计算的链长(子问题规模)38. {39. for(int i=1; i<=n-r+1; i++)//n-r+1为最后一个r链的前边界40. {41. int j = i+r-1;//计算前边界为r,链长为r的链的后边界42.43. m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];//将链ij划分为A(i) * ( A[i+1:j] )44.45. s[i][j] = i;46.47. for(int k=i+1; k<j; k++)48. {49. //将链ij划分为( A[i:k] )* (A[k+1:j]) 50. int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];51. if(t<m[i][j])52. {53. m[i][j] = t;54. s[i][j] = k;55. }56. }57. }58. }59. return m[1][L-1];60. }61.62. void Traceback(int i,int j,int **s)63. {64. if(i==j) return;65. Traceback(i,s[i][j],s);66. Traceback(s[i][j]+1,j,s);67. cout<<"Multiply A"<<i<<","<<s[i][j];68. cout<<" and A"<<(s[i][j]+1)<<","<<j<<endl;69. }上述迭代算法的运行过程如下图所示:当R=2时,先迭代计算出: m[1:2]=m[1:1]+m[2:2}+p[0]*p[1]*p[2]; m[2:3]=m[2:2]+m[3:3]+p[1]*p[2]*p[3];。

矩阵连乘算法

矩阵连乘算法

福州大学数学与计算机科学学院《计算机算法设计与分析》上机实验报告(2)i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。

由于在计算是并不知道断开点k的位置,所以k还未定。

不过k的位置只有j-i个可能。

因此,k是这j-i个位置使计算量达到最小的那个位置。

综上,有递推关系如下:若将对应m[i][j]的断开位置k记为s[i][j],在计算出最优值m[i][j]后,可递归地由s[i][j]构造出相应的最优解。

s[i][j]中的数表明,计算矩阵链A[i:j]的最佳方式应在矩阵Ak和Ak+1之间断开,即最优的加括号方式应为(A[i:k])(A[k+1:j)。

从s[1][n]记录的信息可知计算A[1:n]的最优加括号方式为(A[1:s[1][n]])(A[s[1][n]+1:n]),进一步递推,A[1:s[1][n]]的最优加括号方式为(A[1:s[1][s[1][n]]])(A[s[1][s[1][n]]+1:s[1][s[1][n]]] )。

同理可以确定A[s[1][n]+1:n]的最优加括号方式在s[s[1][n]+1][n]处断开...照此递推下去,最终可以确定A[1:n]的最优完全加括号方式,及构造出问题的一个最优解。

3、动态规划迭代算法设计:用动态规划迭代方式解决此问题,可依据其递归式自底向上的方式进行计算。

在计算过程中,保存已解决的子问题的答案。

每个子问题只计算一次,而在后面需要时只需简单检查一下,从而避免了大量的重复计算,最终得到多项式时间的算法。

4、算法代码:1.//3d1-2 矩阵连乘动态规划迭代实现2.//A1 30*35 A2 35*15 A3 15*5 A4 5*10 A5 10*20 A6 20*253.//p[0-6]={30,35,15,5,10,20,25}4.#include "stdafx.h"5.#include <iostream>ing namespace std;7.8.const int L = 7;9.10.int MatrixChain(int n,int **m,int **s,int *p);11.void Traceback(int i,int j,int **s);//构造最优解12.13.int main()14.{15.int p[L]={30,35,15,5,10,20,25};16.17.int **s = new int *[L];18.int **m = new int *[L];19.for(int i=0;i<L;i++)20. {21. s[i] = new int[L];22. m[i] = new int[L];23. }24.25. cout<<"矩阵的最少计算次数为:"<<MatrixChain(6,m,s,p)<<endl;26. cout<<"矩阵最优计算次序为:"<<endl;27. Traceback(1,6,s);28.return 0;29.}30.31.int MatrixChain(int n,int **m,int **s,int *p)32.{33.for(int i=1; i<=n; i++)34. {35. m[i][i] = 0;36. }37.for(int r=2; r<=n; r++) //r为当前计算的链长(子问题规模)38. {39.for(int i=1; i<=n-r+1; i++)//n-r+1为最后一个r链的前边界40. {41.int j = i+r-1;//计算前边界为r,链长为r的链的后边界42.43. m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];//将链ij划分为A(i) * ( A[i+1:j] )44.45. s[i][j] = i;46.47.for(int k=i+1; k<j; k++)48. {49.//将链ij划分为( A[i:k] )* (A[k+1:j])50.int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];51.if(t<m[i][j])52. {53. m[i][j] = t;54. s[i][j] = k;55. }56. }57. }58. }59.return m[1][L-1];60.}61.62.void Traceback(int i,int j,int **s)63.{64.if(i==j) return;65. Traceback(i,s[i][j],s);66. Traceback(s[i][j]+1,j,s);67. cout<<"Multiply A"<<i<<","<<s[i][j];68. cout<<" and A"<<(s[i][j]+1)<<","<<j<<endl;69.}上述迭代算法的运行过程如下图所示:当R=2时,先迭代计算出: m[1:2]=m[1:1]+m[2:2}+p[0]*p[1]*p[2];m[2:3]=m[2:2]+m[3:3]+p[1]*p[2]*p[3];。

实验一、矩阵连乘问题

实验一、矩阵连乘问题

实验一、矩阵连乘问题问题描述与实验目的:给定n个矩阵A1,A2,…,A n,其中,A i与A j+1是可乘的,i=1,2,…,n-l。

你的任务是要确定矩阵连乘的运算次序,使计算这n个矩阵的连乘积A1A2…A n时总的元素乘法次数达到最少。

例如:3个矩阵A1,A2,A3,阶分别为10×100、100×5、5×50,计算连乘积A1A2A3时按(A1A2)A3所需的元素乘法次数达到最少,为7500次。

输入测试数据有若干组,每组测试数据有2行。

每组测试数据的第1行是一个整数n,(0<n<20),第2行是n+1个正整数p、p 1、p2、…、pn,这些整数不超过100,相邻两个整数之间空一格,他们表示n个矩阵A1,A2,…,A n,的阶pi-1 pi,i=1,2,…,n。

输入直到文件结束。

输出对输入中的每组测试数据,输出2行。

先在一行上输出“Case #”,其中“#”是测试数据的组号(从1开始),再在第2行上输出计算这n个矩阵的连乘积A1A2…An时最少的总的元素乘法次数,再空一格,接着在同一行上输出矩阵连乘的添括号形式。

注意:最外层括号应去掉。

实验结果:输入样例310 100 5 50450 10 40 30 5输出样例Case 17500 (A1A2)A3Case 210500 A1(A2(A3A4))实验报告要求:1.先分析要点、写出动态方程2.提供能正确运行的程序。

要有一般性,即可同时处理若干组数据,每组2行。

3.设计、调试中的问题及实验体会。

矩阵连乘问题实验报告

矩阵连乘问题实验报告

一、实验目的通过本次实验,加深对动态规划算法的理解和应用,掌握解决矩阵连乘问题的方法,提高算法分析和设计能力。

二、实验原理矩阵连乘问题是指给定n个矩阵,每个矩阵都与它的前一个矩阵可乘,求计算这些矩阵连乘积的最优计算次序,以使计算过程中所需的数乘次数最少。

由于矩阵乘法满足结合律,因此可以通过加括号的方式确定不同的计算次序。

三、实验步骤1. 问题描述:给定n个矩阵A1, A2, ..., An,其中Ai与Ai-1是可乘的。

求计算矩阵连乘积A1A2...An的最优计算次序,使得计算过程中所需的数乘次数最少。

2. 输入数据:矩阵个数n,每个矩阵的规模。

3. 输出结果:计算矩阵连乘积的最优计算次序和最少数乘次数。

4. 算法设计:- 定义一个二维数组m[i][j],其中m[i][j]表示计算矩阵AiAi-1...Aj的最少数乘次数。

- 初始化m[i][i] = 0,因为单个矩阵无需计算。

- 对于每个子问题A[i:j],计算m[i][j]的最小值:- 遍历k从i到j-1,将问题分解为A[i:k]和Ak+1:j,计算m[i][k]和m[k+1][j]的和,并加上k个矩阵的维度乘积。

- 取上述和的最小值作为m[i][j]的值。

5. 递归关系:- 当i = j时,m[i][j] = 0。

- 当i < j时,m[i][j] = min(m[i][k] + m[k+1][j] + p[i-1]p[k]p[j]),其中k从i到j-1,p[i-1]表示矩阵Ai-1的行数,p[j]表示矩阵Aj的列数。

6. 自底向上计算:- 从m[1][1]开始,按照递归关系计算m[1][2],m[1][3],...,m[1][n]。

- 然后计算m[2][3],m[2][4],...,m[2][n],以此类推,直到计算m[1][n]。

7. 输出最优计算次序:- 从m[1][n]开始,根据递归关系和子问题的最优解,逐步确定每个子问题的最优计算次序,直到得到整个问题的最优计算次序。

矩阵连乘实验报告总结

矩阵连乘实验报告总结

一、实验背景与目的矩阵连乘问题是一个经典的算法问题,它涉及给定一系列矩阵,确定这些矩阵的最佳乘积顺序,以最小化乘法操作的次数。

本实验旨在通过动态规划算法解决矩阵连乘问题,加深对动态规划方法的理解,并提高算法分析与设计的能力。

二、实验内容与步骤1. 问题描述与理解:- 给定n个矩阵A1, A2, ..., An,其中任意两个相邻矩阵都是可乘的。

- 目标是确定计算这些矩阵连乘积的最佳顺序,以最小化所需的乘法次数。

2. 算法分析:- 使用动态规划方法,通过将问题分解为子问题并存储子问题的解来求解。

- 设定m[i, j]表示矩阵Ai到Aj的最佳乘积顺序的乘法次数。

3. 动态规划过程:- 初始化m[i, i] = 0,因为单个矩阵不需要乘法。

- 对于长度为k的矩阵序列,通过遍历所有可能的分割点,计算m[i, j]的最小值。

- 具体步骤包括:- 对于每个可能的k(1 ≤ k ≤ n-1),- 对于每个起始矩阵i(1 ≤ i ≤ n-k),- 计算m[i, i+k-1]和m[i+k, j],- 更新m[i, j]为m[i, i+k-1] + m[i+k, j] + p[i-1] p[i] p[i+k]。

4. 代码实现:- 使用C或Java等编程语言实现动态规划算法。

- 编写辅助函数来计算矩阵的乘法次数。

三、实验结果与分析1. 实验结果:- 通过实验,成功实现了矩阵连乘问题的动态规划算法。

- 得到了计算给定矩阵序列连乘积所需的最小乘法次数。

2. 结果分析:- 动态规划方法有效地解决了矩阵连乘问题,避免了穷举法的指数级时间复杂度。

- 通过分析子问题的解,我们可以找到整个问题的最优解。

四、实验总结与反思1. 实验收获:- 加深了对动态规划方法的理解,特别是如何通过子问题的解来构建整个问题的解。

- 学会了如何将实际问题转化为动态规划问题,并使用代码实现算法。

2. 反思与展望:- 实验过程中遇到了一些挑战,如理解子问题的定义和计算最优子结构的策略。

算法分析实验三报告

算法分析实验三报告

《算法设计与分析》实验报告目录一、实验内容描述和功能分析.二、算法过程设计.三、程序调试及结果(附截图).四、源代码(附源代码).一、实验内容描述和功能分析.1.矩阵连乘问题内容描述:给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2 ,…,n-1。

如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。

功能分析:输入包含多组测试数据。

第一行为一个整数C,表示有C 组测试数据,接下来有2*C行数据,每组测试数据占2行,每组测试数据第一行是1个整数n,表示有n个矩阵连乘,接下来一行有n+1个数,表示是n个矩阵的行及第n个矩阵的列,它们之间用空格隔开。

输出应该有C行,即每组测试数据的输出占一行,它是计算出的矩阵最少连乘积次数。

例如:输入:1输出:7500310 100 5 502.Pebble Merging内容描述:在一个圆形操场的四周摆放着n 堆石子。

现要将石子有次序地合并成一堆。

规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。

试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。

编程任务:对于给定n堆石子,编程计算合并成一堆的最小得分和最大得分。

功能分析:输入由多组测试数据组成。

每组测试数据输入的第1 行是正整数n,1≤n≤100,表示有n堆石子。

第二行有n个数,分别表示每堆石子的个数。

对应每组输入,输出的第1 行中的数是最小得分;第2 行中的数是最大得分。

例如:输入:4 输出:434 45 9 54二、算法过程设计.1.矩阵连乘问题矩阵连乘问题是通过设置数组,利用数组的横竖坐标来进行矩阵对应行与列的计算。

2.Pebble Merging这个问题也是跟数组相关,通过寻找数组中的最大和最小值来进行计算。

三、程序调试及结果(附截图).1.矩阵连乘问题2.Pebble Merging四、源代码(附源代码).1.矩阵连乘问题#include <stdio.h>int main(){ int a[ 50 ] , b[ 50 ][ 50 ] , c[ 50 ][50 ] , z , n;int i , r , j , k , t;scanf("%d",&z);while (z --){ scanf("%d",&n);for (i = 0 ; i <= n ; ++ i) scanf("%d",& a[ i ]);for (i = 1 ; i <= n ; ++ i) b[ i ][ i ] = 0;for (r = 2 ; r <= n ; ++ r)for (i = 1 ; i <= n - r + 1 ; ++ i){ j = i + r - 1;b[ i ][ j ] = b[i + 1][ j ] + a[i - 1] * a[ i ] * a[ j ];c[ i ][ j ] = i;for (k = i + 1 ; k < j ; ++ k){ t = b[ i ][ k ] + b[k + 1][ j ] + a[i - 1] * a[ k ] * a[ j ];if (t < b[ i ][ j ])b[ i ][ j ] = t , c[ i ][ j ] = k;}}printf ("%d\n" , b[ 1 ][ n ]);}return 0;}2.Pebble Merging#include <stdio.h>int main(){ int dpmin[ 200 ][ 200 ] , min[ 200 ][ 200 ] , mins;int dpmax[ 200 ][ 200 ] , max[ 200 ][ 200 ] , maxs;int a[ 200 ] , i , n , j , k , temp , l;while (scanf ("%d" , & n) != EOF){ for (i = 1 ; i <= n ; ++ i) scanf ("%d" , & a[ i ]);for (i = 1 ; i < n ; ++ i) a[i + n] = a[ i ];for (i = 1 ; i < 2 * n ; ++ i){ min[ i ][ i ] = max[ i ][ i ] = 0;dpmax[ i ][ i ] = dpmin[ i ][ i ] = a[ i ];dpmax[ i ][i + 1] = dpmin[ i ][i + 1] = a[ i ] + a[i + 1];min[ i ][i + 1] = max[ i ][i + 1] = a[ i ] + a[i + 1];}for (i = 1 ; i < n - 1; ++ i)for (l = 1 , j = 2 + i ; j < 2 * n ; ++ j , ++ l){ for (k = l + 1 ; k <= j ; ++ k){ if (k == l + 1){ dpmin[ l ][ j ] = dpmin[ l ][k - 1] + dpmin[ k ][ j ] + min[ l ][k - 1] + min[ k ][ j ];if ( l == k - 1 && k != j)min[ l ][ j ] = a[ l ] + min[ k ][ j ];elseif (l != k - 1 && k == j)min[ l ][ j ] = min[ l ][k - 1] + a[ k ];elsemin[ l ][ j ] = min[ l ][k - 1] + min[ k ][ j ]; dpmax[ l ][ j ] = dpmax[ l ][k - 1] + dpmax[ k ][ j ] + max[ l ][k - 1] + max[ k ][ j ];if ( l == k - 1 && k != j)max[ l ][ j ] = a[ l ] + max[ k ][ j ];elseif (l != k - 1 && k == j)max[ l ][ j ] = max[ l ][k - 1] + a[ k ];elsemax[ l ][ j ] = max[ l ][k - 1] + max[ k ][ j ];continue ;}temp = dpmin[ l ][k - 1] + dpmin[ k ][ j ] + min[ l ][k - 1] + min[ k ][ j ];if (temp < dpmin[ l ][ j ]){ dpmin[ l ][ j ] = temp;if ( l == k - 1 && k != j)min[ l ][ j ] = a[ l ] + min[ k ][ j ];elseif (l != k - 1 && k == j)min[ l ][ j ] = min[ l ][k - 1] + a[ k ];elsemin[ l ][ j ] = min[ l ][k - 1] + min[ k ][ j ];}temp = dpmax[ l ][k - 1] + dpmax[ k ][ j ] + max[ l ][k - 1] + max[ k ][ j ];if (temp > dpmax[ l ][ j ]){ dpmax[ l ][ j ] = temp;if ( l == k - 1 && k != j)max[ l ][ j ] = a[ l ] + max[ k ][ j ];elseif (l != k - 1 && k == j)max[ l ][ j ] = max[ l ][k - 1] + a[ k ];elsemax[ l ][ j ] = max[ l ][k - 1] + max[ k ][ j ];} } }mins = dpmin[ 1 ][ n ]; maxs = dpmax[ 1 ][ n ];for (i = 2 ; i <= n ; ++ i){ if (mins > dpmin[ i ][i + n - 1])mins = dpmin[ i ][i + n - 1];if (maxs < dpmax[ i ][i + n - 1])maxs = dpmax[ i ][i + n - 1];}printf ("%d\n%d\n" , mins , maxs);}return 23;}。

数学院的实验报告

数学院的实验报告

实验名称:线性代数矩阵运算实验实验日期:2023年4月10日实验地点:数学院计算机实验室一、实验目的1. 理解矩阵的基本概念和性质。

2. 掌握矩阵的运算方法,包括矩阵的加法、减法、乘法、转置等。

3. 熟悉矩阵运算在科学计算中的应用。

二、实验原理矩阵是一种由数字构成的矩形阵列,是线性代数中的一个基本概念。

矩阵运算包括矩阵的加法、减法、乘法、转置等。

矩阵运算在科学计算、工程应用、经济管理等领域有着广泛的应用。

三、实验仪器与材料1. 计算机2. 线性代数教材3. 矩阵运算软件(如MATLAB)四、实验内容与步骤1. 矩阵的创建与显示(1)创建一个3x3的矩阵A:A = [1 2 3; 4 5 6; 7 8 9](2)创建一个2x2的矩阵B:B = [9 8; 7 6](3)显示矩阵A和B:disp(A)disp(B)2. 矩阵的加法与减法(1)计算矩阵A和B的和:C = A + B(2)计算矩阵A和B的差:D = A - B(3)显示矩阵C和D:disp(C)disp(D)3. 矩阵的乘法(1)计算矩阵A和B的乘积:E = A B(2)显示矩阵E:disp(E)4. 矩阵的转置(1)计算矩阵A的转置:F = A'(2)显示矩阵F:disp(F)五、实验结果与分析1. 矩阵A和B的创建及显示成功,矩阵A为:1 2 34 5 67 8 9矩阵B为:9 87 62. 矩阵A和B的加法运算成功,结果C为:10 1012 11矩阵A和B的减法运算成功,结果D为:-8 -23 03. 矩阵A和B的乘法运算成功,结果E为:57 5439 364. 矩阵A的转置运算成功,结果F为:1 4 72 5 83 6 9六、实验结论通过本次实验,我们掌握了矩阵的基本概念和性质,以及矩阵的运算方法。

实验结果表明,矩阵运算在科学计算、工程应用、经济管理等领域有着广泛的应用。

在实际应用中,熟练掌握矩阵运算对于解决实际问题具有重要意义。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

矩阵连乘实验报告
————————————————————————————————作者: ————————————————————————————————日期:

华北电力大学科技学院
实验报告
实验名称矩阵连乘问题
课程名称计算机算法设计与分析
专业班级:ﻩ软件12K1ﻩﻩ学生姓名:吴旭
学号:121909020124 成绩:
指导老师: 刘老师ﻩ实验日期:2014.11.14
一、实验内容
矩阵连乘问题,给定n个矩阵{A1,A2,…,A n},其中A i与A i+1是可乘的,i=1,2,3…,n-1。

考察这n个矩阵的连乘A1,A2,…,A n。

二、主要思想
由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。

这种计算次序可以用加括号的方式来确定。

若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已经完全加括号,则可依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。

完全加括号的矩阵连乘积可递归的定义为:
(1)单个矩阵是完全加括号的;
(2)矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的
矩阵连乘积B和C的乘积并加括号,即A=(BC)。

运用动态规划法解矩阵连乘积的最优计算次序问题。

按以下几个步骤进行
1、分析最优解的结构
设计求解具体问题的动态规划算法的第1步是刻画该问题的最优解的结构特征。

为方便起见,将矩阵连乘积简记为A[i:j]。

考察计算A[1:n]的最优计算次序。

设这个计算次序矩阵在Ak和A k+1之间将矩阵链断开,1≤k≤n,则其相应的完全加括号方式为((A
…A k)(Ak+1…A n))。

依此次序,先计算A[1:k]和A[k+1:n],然后1
将计算结果相乘得到A[1:n]。

2、建立递归关系
设计动态规划算法的第二步是递归定义最优值。

对于矩阵连乘积的最优计算次序问题,设计算A[i:j],1≤i≤j≤n,所需的最少数乘次数为m[i][j],原问题的最优值为m[1][n]。

当i=j时,A[i:j]=A i为单一矩阵,无需计算,因此m[i][i]=0,i=1,2,…n。

当i<j时,可利用最优子结构性质来计算m[i][j]。

m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。

由于在计算时并不知道断开点k的位置,所以k还未定。

3、计算最优值
根据计算m[i][j]的递归式,容易写一个递归算法计算m[1][n]。

动态规划法解决此问题,可依据递归式以自底向上的方式进行计算,在计算过程中保存已解决的子问题答案。

每个子问题只计算一次,而在后面需要时只要简单查一下,从而避免大量的重复计算,最终得到多项式时间的算法matrixChain。

(见实验代码部分)
4、构造最优解
算法matrixChain只计算出最优值,并没有给出最优解。

但是matrixChain已经记录了构造最优解所需的全部信息。

S[i][j]中的数表明,计算矩阵链A[i:j]的最佳方式应在矩阵Ak和Ak+1之间断开,最优加括号方式为(A[i:k])(A[k+1:j])。

依次构造最优解。

(算法见实
验代码部分)
三、实验结果
四、结果验证
对实验结果进行验证,4个矩阵分别是A1[35*15],A2[15*5],A3[5*10],A4[10*20]。

依递归式有:
M[1][4]=min{0+2500+35×15×20=13000 2625+1000+35×5×20=7125 4375+0+35×10×20=11375
=7125
且k=3。

计算结果正确,证明所编写的程序可正确算出最优解。

五、实验代码
#include<stdio.h>
#defineN100//定义最大连乘的矩阵个数是100
void matrixChain(intp[],int m[N+1][N+1],int s[N+1][N+1])/*用m[i][j]二维数组来存储Ai*.....Aj的最少数乘次数,
用s[i][j]来存储使Ai.....Aj获得最少数乘次数对应的断开位置k,需要注意的是此处的N+1非常关键,虽然只用到的行列下标只从1到N,
但是下标0对应的元素默认也属于该数组,所以数组的长度就应该为N+1*/{
ﻩintn=N;//定义m,s数组的都是n*n的,不用行列下标为0的元素,但包括在该数组中
for(inti=1;i<=n;i++)
m[i][i]=0;/*将矩阵m的对角线位置上元素全部置0,此时应是r=1的情况,表示先计算第一层对角线上个元素的值*/
ﻩfor(intr=2;r<=n;r++)//r表示斜对角线的层数,从2取到n {
ﻩfor(int i=1;i<=n-r+1;i++)//i表示计算第r层斜对角线上第i行元素的值
ﻩ{
ﻩint j=i+r-1;//j表示当斜对角线层数为r,行下标为i时的列下标ﻩﻩm[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];//计算当断开位置为i时对应的数乘次数
ﻩs[i][j]=i;//断开位置为i
ﻩfor(int k=i+1;k<j;k++)
ﻩﻩ{
ﻩﻩint t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];/*计算断开位置k为从i到j(不包括i和j)的所有取值对应的
ﻩﻩ(Ai*.....*Ak)*(Ak+1*.....Aj)的数乘次数*/
ﻩif(t<m[i][j])

ﻩm[i][j]=t;//将Ai*....Aj的最少数乘次数存入m[i][j] ﻩs[i][j]=k;//将对应的断开位置k存入s[i][j]
ﻩﻩﻩﻩ
ﻩﻩ
ﻩ}

ﻩﻩﻩ}
ﻩ}


void traceback(int i,int j,int s[][N+1])//用递归来实现输出得到最小数乘次数的表达式
{
if(i==j)
ﻩ{
printf("A%d",i);

ﻩelse
ﻩ{
ﻩprintf("(");
ﻩﻩtraceback(i,s[i][j],s);
traceback(s[i][j]+1,j,s);
ﻩﻩprintf(")");
}

void main()
{
intn;//用来存储矩阵的个数
intq[2*N];/*用q数组来存储最原始的输入(各矩阵的行和列),主要目的是为了检验这N个矩阵是否满足连乘的条件*/
ﻩint p[N+1],flag=1;/*用p[i-1],p[i]数组来存储A的阶数,flag用来判断这N个矩阵是否满足连乘*/
ﻩintm[N+1][N+1];// 用m[i][j]二维数组来存储Ai*......Aj的最小数乘次数
int s[N+1][N+1];//用s[i][j]来存储使Ai......Aj获得最小数乘次数对应的断开位置k

printf("输入矩阵的个数(注:小于100):");
ﻩscanf("%d",&n);
for(inti=0;i<=2*n-1;i++)//各矩阵的阶数的输入先存入数组q中接受检验
{
ﻩif(i%2==0)
ﻩ{
ﻩﻩprintf("————————\n");
ﻩprintf("*输入A%d的行:",(i/2)+1);
ﻩelse
{
ﻩﻩprintf(" ********列:");
ﻩ}
scanf("%d",&q[i]);
ﻩ}
ﻩfor(i=1;i<=2*n-2;i++)//矩阵连乘条件的检验ﻩ{
ﻩﻩif(i%2!=0&&q[i]!=q[i+1])
ﻩ{
ﻩflag=0;
ﻩﻩbreak;
ﻩ}
ﻩ}
for(int j=1;j<=n-1;j++)

ﻩp[j]=q[2*j];
ﻩ}
ﻩif(flag!=0)
ﻩ{
ﻩﻩp[0]=q[0];
ﻩp[n]=q[2*n-1];
ﻩmatrixChain(p,m,s);
ﻩﻩprintf("式子如下:\n");
ﻩtraceback(1,n,s);
printf("\n");
printf("最少数乘次数为%d\n",m[1][n]); ﻩ}
ﻩelse
ﻩ{
ﻩﻩprintf("这%d个矩阵不能连乘!\n",n);

}
六、实验心得
通过本次实验,我较为透彻的理解了动态规划算法的几个基本步骤。

完成实验后,我认为建立递归关系是很关键的一步,同时也是整个动态规划算法的精髓。

掌握了递归的思想,就可以完成很多不必要的重复计算。

具体到矩阵连乘问题,关键是解决断开点k的位置和最少数乘次数。

总体来说,这次实验不仅让我基本掌握递归的思想,而且进一步提高了自己的自学能力和编程能力,代码运用C语言写出,可以很好的体会C语言和C++的不同点和相同点。

我也体会到,想要理解一个新的算法,必须要通过自己不断的编写程序,不断的思考才能真正的领悟,因此我会不断朝着这个方向努力。

相关文档
最新文档