动态规划算法分析与设计实验报告(矩阵连乘)
10计本算法实验矩阵连乘算法
实验报告4课程数据结构与算法实验名称动态规划(一) 第页班级10计本学号105032010111 姓名陈兴灶实验日期:2012年3月20日报告退发(订正、重做)一、实验目的掌握递归及分治策略的原理和应用。
二、实验环境1、微型计算机一台2、WINDOWS操作系统,Java SDK,Eclipse开发环境三、实验内容必做题:1、编程实现矩阵连乘算法,求出最优值及一个最优解。
附加题:1、开车从a到b会经过n个加油站,给定这n个加油站的距离和油价,及汽车耗油量,汽车油箱的容量为v,编程计算从a到b至少需要花费多少油费。
四、实验步骤和结果第一题:矩阵连乘算法package shiyan4;import java.util.Scanner;public class matrixChain {public static int [][]a;public static int [][]b;public static void matrixchain(int []p,int [][]m,int [][]s){int n=p.length-1;for(int i=1;i<n;i++)m[i][i]=0;for(int r=2;r<=n;r++)for(int i=1;i<=n-r+1;i++){int j=i+r-1;m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];s[i][j]=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];if(t<m[i][j]){m[i][j]=t;s[i][j]=k;}}}}public static void traceback(int [][]s,int i,int j){if(i==j)return ;traceback(s,i,s[i][j]);traceback(s,s[i][j]+1,j);System.out.println("Multiply A"+i+","+s[i][j]+" and A"+(s[i][j]+1)+","+j);}public static void main(String []args){Scanner sc=new Scanner(System.in);System.out.println("输入矩阵个数");int n=sc.nextInt();int []p=new int[n+1];a=new int [n+1][n+1];b=new int [n+1][n+1];System.out.println("输入各矩阵的行数和列数");for(int i=0;i<=n;i++)p[i]=sc.nextInt();matrixchain(p,a,b);System.out.println("最少次数为");System.out.println(a[1][a.length-1]+" ");System.out.println("最优解为");traceback(b,1,n);}}结果:第二题:计算从a到b至少需要花费多少油费package shiyan4;import java.util.Scanner;public class MinPertrolFee {public static float []fee;public static float []distance;public static float v;public static float vh;public static float vs;float money;MinPertrolFee(){Scanner sc=new Scanner(System.in);System.out.println("输入加油站个数");int n=sc.nextInt();fee=new float[n];System.out.println("输入每个加油站油的单价");distance=new float[n];for(int i=1;i<fee.length;i++)fee[i]=sc.nextFloat();System.out.println("输入两两相邻加油站间的距离");for(int i=1;i<distance.length;i++)distance[i]=sc.nextFloat();System.out.println("输入油箱容量");v=sc.nextFloat();System.out.println("输入每公里的耗油量");vh=sc.nextFloat();vs=0;money=0;}public static void minpertrolfee(MinPertrolFee e) {float s=e.v/e.vh,s2;int j,l,k;for(int i=1;i<e.fee.length;i++){float vj=e.distance[i]/e.vh-e.vs;if(vj>0){e.money+=addpertrol(vj,i);e.vs+=vj;}float s1=0;for( j=i;j<e.fee.length&&s>=s1;j++)s1+=e.distance[j];for( l=i,k=i;l<(e.fee.length-1)&&l<=j;l++) {if(e.fee[k]>=e.fee[l+1])break;else continue;}if(l==j&&j!=e.distance.length)s2=e.v/e.vh;else s2=e.distance[l]-e.distance[i];float vj1=s2/e.vh-e.vs;if(vj1>0){e.money+=addpertrol(vj1,i);e.vs+=vj1;}e.vs-=e.distance[i]/e.vh;}System.out.println("所须要最少的钱为"+e.money); }public static float addpertrol(float vj,int i) {return vj*fee[i];}public static void main(String []args){MinPertrolFee e=new MinPertrolFee();minpertrolfee(e);}}结果:五、实验总结1.第二题算法是错的。
动态规划-(矩阵连乘)
12
4、构造最优解
void MatrixChain::Traceback(int i, int j) {
if(i==j) { cout<<'A'<<i; return;} if (i<s[i][j]) cout<<'('; Traceback(i, s[i][j]); if (i<s[i][j])cout<<')'; if(s[i][j]+1<j)cout<<'('; Traceback(s[i][j]+1, j); if(s[i][j]+1<j) cout<<')'; } void MatrixChain::Traceback() { cout<<'('; Traceback(0, n-1); cout<<')'; cout<<endl; }
②当i=j时,A[i:j]=Ai,因此,m[i][i]=0,i=1,2,…,n ③当i<j时,m [ i ] j ] [ m [ i ] k ] [ m [ k 1 ] j ] [ p i 1 p k p j
这里 A i 的维数为 pi1pi
∴可以递归地定义m[i][j]为:
m [i]j] [ m i k j{ m [i]n k [ ] m [k 0 1 ]j] [ p i 1 p kp j}i i j j
根据MatrixChain动态规划算法: ②计算m[i][j]数乘次数
m[2][5]=min m[2][2]+m[3][5]+p1p2p5=13000
动态规划实验报告心得
一、实验背景动态规划是一种重要的算法设计方法,广泛应用于解决优化问题。
本次实验旨在通过实际操作,加深对动态规划算法的理解,掌握其基本思想,并学会运用动态规划解决实际问题。
二、实验内容本次实验主要包括以下几个内容:1. 动态规划算法概述首先,我们对动态规划算法进行了概述,学习了动态规划的基本概念、特点、应用领域等。
动态规划是一种将复杂问题分解为若干个相互重叠的子问题,并存储已解决子问题的解,以避免重复计算的方法。
2. 矩阵连乘问题矩阵连乘问题是动态规划算法的经典问题之一。
通过实验,我们学会了如何将矩阵连乘问题分解为若干个相互重叠的子问题,并利用动态规划方法求解。
实验过程中,我们分析了问题的最优子结构、子问题的重叠性,以及状态转移方程,从而得到了求解矩阵连乘问题的动态规划算法。
3. 0-1背包问题0-1背包问题是另一个典型的动态规划问题。
在实验中,我们学习了如何将0-1背包问题分解为若干个相互重叠的子问题,并利用动态规划方法求解。
实验过程中,我们分析了问题的最优子结构、子问题的重叠性,以及状态转移方程,从而得到了求解0-1背包问题的动态规划算法。
4. 股票买卖问题股票买卖问题是动态规划在实际应用中的一个例子。
在实验中,我们学习了如何将股票买卖问题分解为若干个相互重叠的子问题,并利用动态规划方法求解。
实验过程中,我们分析了问题的最优子结构、子问题的重叠性,以及状态转移方程,从而得到了求解股票买卖问题的动态规划算法。
三、实验心得1. 动态规划算法的思维方式通过本次实验,我深刻体会到了动态规划算法的思维方式。
动态规划算法的核心是将复杂问题分解为若干个相互重叠的子问题,并存储已解决子问题的解。
这种思维方式有助于我们更好地理解和解决实际问题。
2. 状态转移方程的重要性在动态规划算法中,状态转移方程起着至关重要的作用。
它描述了子问题之间的关系,是求解问题的关键。
通过本次实验,我学会了如何分析问题的最优子结构,以及如何建立合适的状态转移方程。
矩阵连乘问题《算法分析报告与设计》
word设计性实验报告课程名称:《算法分析与设计》实验题目:矩阵连乘问题组长:成员一:成员二:成员三:系别:数学与计算机科学系专业班级:指导教师:实验日期:一、实验目的和要求实验目的熟悉动态规划算法设计思想和设计步骤,掌握基本的程序设计方法,培养学生用计算机解决实际问题的能力。
实验要求1、根据实验内容,认真编写源程序代码、上机调试程序,书写实验报告。
2、本实验项目考察学生对教材中核心知识的掌握程度和解决实际问题的能力。
3、实验项目可以采用集中与分散实验相结合的方式进行,学生利用平时实验课时间和课外时间进行实验,要求在学期末形成完整的项目程序设计报告。
二、实验内容提要矩阵连乘问题给定n个矩阵{A1,A2,…,A n},其中,Ai与Ai+1是可乘的,i=1,2,…,n-1。
考查这n 个矩阵的连乘积A1,A2,…,A n。
由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。
这种计算次序可以用加括号的方式来确定。
若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可以依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。
完全加括号的矩阵连乘积可递归地定义为:(1)单个矩阵是完全加括号的;(2)矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘积B和C的乘积并加括号,即A=(BC)。
三、实验步骤下面考虑矩阵连乘积的最优计算次序问题的动态规划方法。
(1)分析最优解的结构(最优子结构性质)设计求解具体问题的动态规划算法的第一步是刻画该问题的最优解结构特征。
对于矩阵乘积的最优计算次序问题也不例外。
首先,为方便起见,降矩阵乘积Ai Ai+1…Aj简记为A[i:j]。
考查计算A[1:n]的最优计算次序。
设这个计算次序在矩阵Ak和Ak+1之间将矩阵链断开,1<=k<n,则其相应的完全加括号方式为((A1…Ak)(Ak+1…An))即依此次序,先计算A[1:k]和A[k+1:n],然后将计算结果相乘得到A[1:n]。
算法设计与分析——矩阵连乘问题(动态规划)
算法设计与分析——矩阵连乘问题(动态规划)⼀、问题描述引出问题之前我们先来复习⼀下矩阵乘积的标准算法。
int ra,ca;//矩阵A的⾏数和列数int rb,cb;//矩阵B的⾏数和列数void matrixMultiply(){for(int i=0;i<ra;i++){for(int j=0;j<cb;j++){int sun=0;for(int k=0;k<=ca;k++){sum+=a[i][k]*b[k][j];}c[i][j]=sum;}}}给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2…,n-1。
如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
例如,给定三个连乘矩阵{A1,A2,A3}的维数分别是10*100,100*5和5*50,采⽤(A1A2)A3,乘法次数为10*100*5+10*5*50=7500次,⽽采⽤A1(A2A3),乘法次数为100*5*50+10*100*50=75000次乘法,显然,最好的次序是(A1A2)A3,乘法次数为7500次。
加括号的⽅式对计算量有很⼤的影响,于是⾃然地提出矩阵连乘的最优计算次序问题,即对于给定的相继n个矩阵,如何确定矩阵连乘的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
⼆、问题分析矩阵连乘也是Catalan数的⼀个常⽤的例⼦,关于时间复杂度的推算需要参考离散数学关于Catalan的内容。
下⾯考虑使⽤动态规划法解矩阵连乘积的最优计算次序问题。
1、分析最优解的结构问题的最优⼦结构性质是该问题可以⽤动态规划求解的显著特征!!!2、建⽴递归关系3、计算最优值public static void matrixChain(int n) {for (int i = 1; i <= n; i++) {m[i][i] = 0;}for (int r = 2; r <= n; r++) {//i与j的差值for (int i = 1; i <= n - r + 1; i++) {int j = i + r - 1;m[i][j] = m[i + 1][j] + p[i - 1] * p[i] * p[j];s[i][j] = 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];if (t < m[i][j]) {m[i][j] = t;s[i][j] = k;}}}}}4、构造最优解public static void traceback(int i, int j) {if (i == j) {System.out.printf("A%d", i); // 输出是第⼏个数据return;}System.out.printf("(");traceback(i, s[i][j]);// 递归下⼀个数据System.out.printf(" x ");traceback(s[i][j] + 1, j);System.out.printf(")");}三、总结。
动态规划算法实验报告
南京信息工程大学滨江学院实验(实习)报告1.实验目的动态规划通常用来求解最优化问题。
通过本次实验掌握动态规划算法。
通过矩阵连乘问题和0-1背包问题实现动态规划算法。
学会刻画问题的最优结构特征,并利用最优化问题具有的重叠子问题性质,对每个子问题求解一次,将解存入表中,当再次需要这个子问题时直接查表,每次查表的代价为常量时间。
2.实验内容及分析设计过程1.矩阵链乘法问题矩阵链乘法问题可描述如下:给定个矩阵的链,矩阵的规模为,求完全括号方案,使得计算乘积所需的标量乘法次数最少。
令m[i,j]表示计算矩阵所需标量乘法次数的最小值,那么,原问题的最优解计是m[1,n]。
最小代价括号化方案的递归求解公式为采用自底向上表格法代替上述递归算法来计算最优代价。
为了实现自底向上方法,我们必须确定计算m[i,j]时需要访问哪些其他表项。
上述公式显示,j-i+l 个矩阵链相乘的最优计算代价m[i,j] 只依赖于那些少于j-i+l 个矩阵链相乘的最优计算代价。
因此,算法应该按长度递增的顺序求解矩阵链括号化问题,并按对应的顺序填写表m。
对如下输入A1 A2 A3 A4 A5 A630⨯35 35⨯15 15⨯5 5⨯10 10⨯20 20⨯25程序运行结果为2.背包问题给定n 个重量为价值为的物品和一个承重为W 的背包。
求这些物品中最有价值的一个子集,并且要能装到背包中。
设V[i,j]是能够放进承重量为j 的背包的前i 个物品中最有价值子集的总价值。
则递推关系为初始条件V[0,j]=0(j>=0),V[i,0]=0(i>=0) 我们的目标是求V[n ,W]。
递归式给出了V[i,j]的计算顺序,V[i,j]只依赖与前一行的那些项。
故可以逐行计算V[i,j].对于物品数量n=5,w[n]={2,2,6,5,4},v[n]={6,3,5,4,6},背包总重量c=10 程序运行结果为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个矩阵,每个矩阵都与它的前一个矩阵可乘,求计算这些矩阵连乘积的最优计算次序,以使计算过程中所需的数乘次数最少。
由于矩阵乘法满足结合律,因此可以通过加括号的方式确定不同的计算次序。
三、实验步骤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. 反思与展望:- 实验过程中遇到了一些挑战,如理解子问题的定义和计算最优子结构的策略。
矩阵链乘法(动态规划)
矩阵链乘法(动态规划)
⼀题意描述:
给定由n个要相乘的矩阵构成的序列(链)<A1,A2,A3,····A n>。
由于矩阵满⾜结合律(加括号⽅式表⽰结合⽅式),不同的计算⽅式导致的求出最终计算结果的代价相异,有的花的时间很少,有的⽅式所花时间很多,那么下⾯的任务就是求出算出结果所需要的最少时间及⼀个最优解。
⼆思路分析:
设p(n)表⽰⼀串n个矩阵可能的加全部括号⽅案数。
当n=1时,只有⼀个矩阵,此时p(1)=1。
当n>=2时,⼀个加全部括号的矩阵乘积等于两个加全部括号的⼦矩阵乘积的乘积,⽽且这两个⼦乘积之间的分裂可能发⽣在第k个和第k+1个矩阵之间,其中k=1,2,····,n-1;因此可以求得递归式:
1.找局部最优解:把问题:转化成两个最优⼦问题:及
2.构造递归解:
⾸先定义m[i,j]为解决⼦问题A[i....j]的最⼩计算次数,那么解决整个问题A[1,n]所花的最⼩时间为m[1,n]。
那么递归⽅程可以写成如下形式:
为了跟踪如何构造⼀个最优解我们可以定义s[i,j]为这样的⼀个k值,在该处分裂乘积后可得⼀个最优解。
3.构造函数进⾏求解
输出最优路径的函数⾃⼰编写,经过调⽤数组s[i][j]即可。
动态规划算法实验报告
实验标题1、矩阵连乘2、最长公共子序列3、最大子段和4、凸多边形最优三角剖分5、流水作业调度6、0-1背包问题7、最优二叉搜索树实验目的掌握动态规划法的基本思想和算法设计的基本步骤。
实验内容与源码1、矩阵连乘#include<iostream>#include<cstdlib>using namespace std;const int size=4;//ra,ca和rb,cb分别表示矩阵A和B的行数和列数void matriMultiply(int a[][4],int b[][4],int c[][4],int ra ,int ca,int rb ,int cb ) {if(ca!=rb) cerr<<"矩阵不可乘";for(int i=0;i<ra;i++)for(int j=0;j<cb;j++){int sum=a[i][0]*b[0][j];for(int k=1;k<ca;k++)sum+=a[i][k]*b[k][j];c[i][j]=sum;}}void MatrixChain(int *p,int n,int m[][4],int s[][4]){for(int i=1;i<=n;i++) m[i][i]=0;//对角线for(int r=2;r<=n;r++)//外维for(int i=1;i<=n-r+1;i++)//上三角{int j=i+r-1;m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];s[i][j]=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];if(t<m[i][j]){m[i][j]=t;s[i][j]=k;}}}}void Traceback(int i,int j,int s[][4]){if(i == j){cout<<"A"<<i;}else if(i+1 == j){cout<<"(A"<<i<<"A"<<j<<")";}else{cout<<"(";Traceback(i,s[i][j],s);Traceback(s[i][j]+1,j,s);cout<<")";}}int main(){int w;cout<<"矩阵个数:";cin>>w;int p[w],s[w][w];cout<<"输入矩阵A1维数:";cin>>p[0]>>p[1];for(int i=2 ; i<=w ; i++){int m = p[i-1];cout<<"输入矩阵A"<<i<<"维数:";cin>>p[i-1]>>p[i];if(p[i-1] != m){cout<<endl<<"维数不对,矩阵不可乘!"<<endl;exit(1);}}Traceback(1,w,s);return 0;}运行结果2、最长公共子序列#include<cstring>#include<iostream>#define N 100using namespace std;//str1存储字符串x,str2存储字符串ychar str1[N],str2[N];//lcs存储最长公共子序列char lcs[N];//c[i][j]存储str1[1...i]与str2[1...j]的最长公共子序列的长度int c[N][N];//flag[i][j]==0为str1[i]==str2[j]//flag[i][j]==1为c[i-1][j]>=s[i][j-1]//flag[i][j]==-1为c[i-1][j]<s[i][j-1]int flag[N][N];//求长度int LCSLength(char *x, char *y){int i,j;//分别取得x,y的长度int m = strlen(x);int n = strlen(y);for(i=1;i<=m;i++)c[i][0] = 0;for(i=0;i<=n;i++)c[0][i] = 0;for(i=1;i<=m;i++)for(j=1;j<=n;j++){if(x[i-1]==y[j-1]){c[i][j] = c[i-1][j-1] +1;flag[i][j] = 0;}else if(c[i-1][j]>=c[i][j-1]){c[i][j] = c[i-1][j];flag[i][j] = 1;}else{c[i][j] = c[i][j-1];flag[i][j] = -1;}}return c[m][n];}//求出最长公共子序列char* getLCS(char *x, char *y,int len,char *lcs) {int i = strlen(x);int j = strlen(y);while(i&&j){if(flag[i][j]==0){lcs[--len] = x[i-1];i--;j--;}else if(flag[i][j]==1)i--;elsej--;}return lcs;}int main(){int i;cout<<"请输入字符串x:"<<endl;cin>>str1;cout<<"请输入字符串y:"<<endl;cin>>str2;int lcsLen = LCSLength(str1,str2);cout<<"最长公共子序列长度:"<<lcsLen<<endl;char *p = getLCS(str1,str2,lcsLen,lcs);cout<<"最长公共子序列为:";for(i=0;i<lcsLen;i++)cout<<lcs[i]<<" ";return 0;}运行结果3、最大子段和//分治法求最大子段和#include<iostream>using namespace std;int MaxSubSum(int *a,int left,int right){int sum=0;if(left==right) sum=a[left]>0?a[left]:0;else{int center = (left+right)/2;//最大子段和在左边int leftsum=MaxSubSum(a,left,center);//最大子段和在右边int rightsum=MaxSubSum(a,center+1,right);//最大子段和在中间int s1=0;int lefts=0;for(int i=center;i>=left;i--){lefts+=a[i];if(lefts>s1) s1=lefts;}int s2=0;int rights=0;for(int i=center+1;i<=right;i++){rights+=a[i];if(rights>s2) s2=rights;}sum=s1+s2;//前后子段和相加//判断最大子段和if(sum>leftsum)sum=leftsum;if(sum>rightsum) sum=rightsum;}return sum;}int MaxSum(int *a,int n){return MaxSubSum(a,1,n-1);}int main(){int a[8]={2,-3,-5,4,1,7,1,-5};cout<<"最大子段和为:"<<MaxSum(a,8);return 0;}//动态规划法#include<iostream>using namespace std;int MaxSum(int *a,int n){int sum=0,b=0;for(int i=1;i<n;i++)//此处不能=n,{if(b>0) b+=a[i];else b=a[i];if(b>sum) sum=b;}return sum;}int main(){int a[8]={2,-3,-5,4,1,7,1,-5};cout<<"最大子段和为:"<<MaxSum(a,8);return 0;}运行结果4、凸多边形最优三角剖分#include<iostream>#include<cmath>#include<cstdlib>#define N 50using namespace std;struct point{int x;int y;};int distance(point X, point Y)//两点距离{int dis = (Y.x-X.x)*(Y.x-X.x) + (Y.y-X.y)*(Y.y-X.y);return (int)sqrt(dis);}int w(point a, point b, point c)//权值{return distance(a,b) + distance(b,c) + distance(a,c);}bool JudgeInput()//判断是否能构成凸多边形{point *v; //记录凸多边形各顶点坐标int *total; //记录坐标在直线方程中的值int m,a,b,c;cout<<"请输入凸多边形顶点个数:";cin>>m;int M = m-1;for(int i=0 ; i<m ; i++){cout<<"输入顶点v"<<i<<"的坐标:";cin>>v[i].x>>v[i].y;}//根据顶点坐标判断是否能构成一个凸多边形for(int j=0 ; j<m ; j++){int p = 0;int q = 0;if(m-1 == j){a = v[m-1].y - v[0].y;b = v[m-1].x - v[0].y;c = b * v[m-1].y - a * v[m-1].x;}else{a = v[j].y - v[j+1].y;b = v[j].x - v[j+1].x;c = b * v[j].y - a * v[j].x;}for(int k=0 ; k<m ; k++){total[k] = a * v[k].x - b * v[k].y + c;if(total[k] > 0){p = p+1;}else if(total[k] < 0){q = q+1;}}if((p>0 && q>0) || (p==0 && q==0)){cout<<"无法构成凸多边形!"<<endl;exit(1);}}}bool minWeightTriangulation()//计算最优值算法{int M;int **t, **s;point *v;for(int i=1 ; i<=M ; i++)t[i][i] = 0;for(int r=2 ; r<=M ; r++)for(int i=1 ; i<=M-r+1 ; i++){int j = i+r-1;t[i][j] = t[i+1][j] + w(v[i-1],v[i],v[j]);s[i][j] = i;for(int k=i+1 ; k<i+r-1 ; k++){int u = t[i][k] + t[k+1][j] + w(v[i-1],v[k],v[j]);if(u < t[i][j]){t[i][j] = u;s[i][j] = k;}}}return true;}void Traceback(int i, int j, int **s){if(i == j)return;Traceback(i,s[i][j],s);Traceback(s[i][j]+1,j,s);cout<<"三角形:v"<<i-1<<"v"<<s[i][j]<<"v"<<j<<endl;}int main(){int **s; //记录最优三角剖分中所有三角形信息int **t; //记录最优三角剖分所对应的权函数值point *v; //记录凸多边形各顶点坐标int *total; //记录坐标在直线方程中的值int M=0;t = new int *[N];s = new int *[N];for(int i=0 ; i<N ; i++){t[i] = new int[N];s[i] = new int[N];}v = new point[N];total = new int[N];if(JudgeInput()){if(minWeightTriangulation()){Traceback(1,M,s);cout<<endl;cout<<"最优权值之和为:"<<t[1][M]<<endl;}}return 0;}运行结果:5、流水作业调度#include<iostream>#define N 100using namespace std;class Jobtype{public:/* int operator<=(Jobtype a)const{return(key<=a.key);}*/int key;int index;bool job;};void sort(Jobtype *d,int n){int i,j;Jobtype temp;bool exchange; //交换标志for(i = 0;i < n;i ++){ //最多做n-1趟排序exchange = false; //本趟排序开始前,交换标志应为假for(j = n - 1;j >= i;j --)if(d[j+1].key < d[j].key){temp = d[j+1];d[j+1] = d[j];d[j] = temp;exchange=true; //发生了交换,故将交换标志置为真}if(!exchange) //本趟排序未发生交换,提前终止算法return;}}int FlowShop(int n,int *a,int *b,int *c){Jobtype *d = new Jobtype[n];for(int i=0;i<n;i++)//初始化{d[i].key=a[i]>b[i]?b[i]:a[i];// 执行时间d[i].job=a[i]<=b[i];// 作业组d[i].index=i;//作业序号}sort(d,n);;int j=0;int k=n-1;for(int i=0;i<n;i++)//最优调度{if(d[i].job){c[j++]=d[i].index;}else{c[k--]=d[i].index;}}j=a[c[0]];k=j+b[c[0]];for(int i=1;i<n;i++){j+=a[c[i]];k=j<k?k+b[c[i]]:j+b[c[i]];}delete d;//回收空间return k;//返回调度时间}int main(){int n,*a,*b,*c;cout<<"作业数:";cin>>n;Jobtype *d = new Jobtype[N];a=new int[N];b=new int[N];c=new int[N];cout<<"请输入作业号和时间:";for(int i=0;i<n;i++){cin>>d[i].index>>d[i].key;}cout << endl;int k=FlowShop(n,a,b,c);cout<<"\n调度时间:"<<k<<endl;cout<<"最优调度序列:";for (int i = 0; i < n; i++) // 输出最优调度序列{cout << c[i] << " ";}return 0;}运行结果:6、0-1背包问题#include <iostream>#include <iomanip>using namespace std;const int C=10;//容量const int N=5;//个数int max(const int a,const int b){return a>b?a:b;}int min(const int a,const int b){return a<b?a:b;}/*m为记录数组m[i][j]代表在剩有j容量的条件下,从i开始往后的物品中可以取得的最大价值w为重量数组,v为价值数组n为物品个数,c为开始容量则m[1][c]即此背包能剩下的最大价值*/void knapsack(int **m,int n, int c,int *w, int *v){int jMax = min(w[n]-1,c);//前n-1个物品for(int j=0;j<=jMax;j++)m[n][j]=0;for(int j=w[n];j<=c;j++)m[n][j]=v[n];for(int i=n-1;i>1;i--){jMax=min(w[i]-1,c);for(int j=0;j<=jMax;j++)m[i][j] = m[i+1][j];for(int j=w[i];j<=c;j++)m[i][j] = max(m[i+1][j],m[i+1][j-w[i]]+v[i]);}m[1][c]=m[2][c];if(c>=w[1])m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);}//找出最优解,0表示不能装,1表示能装void traceback(int **m,int n,int c,int *x,int *w){for(int i=1;i<n;i++){if(m[i][c]==m[i+1][c]) x[i]=0;else{x[i]=1;c-=w[i];}}x[n]=(m[n][c]==0)?0:1;}int main(){int *v=new int[N+1];int *w=new int[N+1];int **m=new int* [N+1];int *x=new int [N+1];for(int i=0;i<N+1;i++){m[i]=new int[C+1];}cout<<"输入重量序列,"<<N<<"个"<<endl;for(int i=1;i<=N;i++)cin>>w[i];cout<<"输入价值序列,"<<N<<"个"<<endl;for(int i=1;i<=N;i++)cin>>v[i];knapsack(m,N,C,w,v);traceback(m,N,C,x,w);cout<<"最优值:"<<m[1][C]<<endl;cout<<"是否装入背包的情况:";for(int i=1;i<=N;i++){cout<<x[i];}for(int i=0;i<N+1;i++){delete m[i];}delete []m;return 0;}运行结果7、最优二叉搜索树#include<iostream>#include<cmath>#include<limits>#define N 100using namespace std;const double MAX = numeric_limits<double>::max(); //double的最大值//a[i]为结点i被访问的概率//b[i]为“虚结点”i被访问的概率//m[i][j]用来存放子树(i,j)的期望代价//w[i][j]用来存放子树(i,j)的所有结点(包括虚结点)的a,b概率之和//s[i][j]用来跟踪root的void OptimalBinarySearchTree(double *a,double *b,int n){int s[N][N];double m[N][N];double w[N][N];int i,j,l,r;for(i=1; i<=n+1; i++){m[i][i-1] = b[i-1];w[i][i-1] = b[i-1];}for(l=1; l<=n; l++){for(i=1; i<=n-l+1; i++){j = l+i-1;m[i][j] = MAX;w[i][j] = w[i][j-1] + a[j] +b[j];for(r=i; r<=j; r++){double k = m[i][r-1] + w[i][j] + m[r+1][j];if(k<m[i][j]){m[i][j] = k;s[i][j] = k;}}}}cout<<m[1][n];}int main(){double a[N],b[N];int n;double sum = 0;int i,j,l;cout<<"请输入关键字的个数:"<<endl;cin>>n;cout<<"请输入每个关键字的概率:"<<endl;for(i=1; i<=n; i++){cin>>a[i];sum += a[i];}cout<<"请输入每个虚拟键的概率:"<<endl;for(i=0; i<=n; i++){cin>>b[i];sum += b[i];}if(abs(sum-1)>0.01){cout<<"输入的概率和不为1,请重新输入"<<endl;}cout<<"最优二叉查找树的期望搜索代价为:";OptimalBinarySearchTree(a,b,n);return 0;}运行结果:实验总结通过实现动态规划的这个题目,对动态规划算法有了进一步的了解。
实验3-矩阵连乘
实验3 矩阵连乘一、 实验目的1. 理解动态规划的OS1和OS2原则OS1: Overlapping Subproblems; OS2: Optimal Substructure.2. 进一步理解先做证明、再做设计、最后写程序的算法设计过程对于矩阵连乘的效率提高问题,要求实验者按步骤给出从最初的思路到最终的程序,这一算法设计与实现过程。
3. 矩阵连乘动态规划算法的优化在格子设计、观察程序输出等的基础上,探讨提高矩阵连乘动态规划算法效率的技术。
二、 实验环境C/C++编程环境 或 任何编程语言环境三、 实验内容1. 矩阵连乘问题的描述输入:n 个矩阵12n A ,A ,...,A输出:×××12n A A ...A 所需要的最少乘法次数OptimalMC (按蛮力法计算矩阵m nA ×与n pB ×相乘所需标量乘法次数=m n p ××),并给出得到这个OptimalMC 的12n A ,A ,...,A 乘法次序。
若以二叉树形式表示乘法次序,对于234×××1A A A A ,一种乘法次序,如图1所示:图1 矩阵连乘的乘法次序示例上图表示()()234×××1A A A A2. 矩阵连乘问题的算法设计请实验者按下述步骤设计矩阵连乘问题的动态规划算法:2.1 写出求解OptimalMC 的递推式注意:应指出递推式中的哪些部分表示状态变量、哪些部分表示动作、哪些部分表示最优解。
并给出递推式的初始条件。
2.2 证明2.1中给出的递推式的正确性证明方法,可采用Copy & Paste 方法。
若递推式成立,则称递推式满足OS2: Optimal Substructure 原则。
2.3 格子设计依据递推式:1)画出二维内存单元格的计算规则若子问题(由单元格表示)之间存在重叠(即按计算规则,单元格中的数据存在依赖关系),则称本问题满足OS1: Overlapping Subproblems 。
动态规划实现矩阵链乘法问题
动态规划实现矩阵链乘法问题矩阵链乘法问题( matrix-chain multiplication problem ) (1)问题描述 给定n个矩阵的链<A 1 ,A 2 ,…,A n >,其中i=1,2,…,n,矩阵A i的维数为p i-1 ×p i。
求⼀个完全“括号化⽅案”,使得计算乘积A 1 A 2 …A n 所需的标量乘法次数最⼩ (2)最优括号化⽅案的结构特征 ⽤记号 A i,j表⽰ A i A i+1 …A j通过加括号后得到的⼀个最优计算模式,且恰好在A k与A k+1之间分开。
则“前缀”⼦链A i A i+1 …A k必是⼀个最优的括号化⼦⽅案,记为A i,k;同理“后缀”⼦链A k+1 A k+2 …A j也必是⼀个最优的括号化⼦⽅案,记为A k+1,j。
(3)⼀个递归求解的⽅案 对于矩阵链乘法问题,我们将所有对于1≤i≤j≤n确定A i A i+1 …A j的最⼩代价括号⽅案作为⼦问题。
令m[i,j]表⽰计算矩阵A i,j所需要的标量乘法的次数最⼩值,则最优解就是计算A i...n所需的最低代价就是m[1,n] 递归定义m[i,j]。
①对于i=j的情况下,显然有m=0,不需要做任何标量乘法运算。
所以,对于所有的i=1、2......n,m[i,i] = 0. ②当i < j的情况,就按照最优括号化⽅案的结构特征进⾏计算m[i,j]。
假设最优括号化⽅案的分割点在矩阵A k和A k+1之间,那么m的值就是A i...k和A k+1...j的代价加上两者量程的代价的最⼩值。
即。
该公式的假设是最优分割点是已知的,但是实际上不知道。
然⽽,k只有j-i中情况取值。
由于最优分割点k必定在i~j内取得,只需要检查所有可能的情况,找到最优解即可。
可以得出⼀个递归公式 m只是给出了⼦问题最优解的代价,但是并未给出构造最优解的⾜够信息(即分割点的位置信息)。
所以,在此基础之上,我们使⽤⼀个⼆维数组s[i,j]来保存 A i A i+1 …A j 的分割点位置k。
动态规划算法分析与设计实验报告(矩阵连乘)
算法分析与设计实验报告实验题目:动态规划算法的设计与实现1、实验目的通过本实验,掌握动态规划算法的设计的基本思想,进一步提高学生的编程能力。
2、实验内容:给定n个矩阵{A1,A2,…,A n},其中A i与A i+1是可乘的,i=1,2…,n-1。
如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
3、源程序if (t<u) //返回t,k中较小的值,并记录断点处k{ u=t; s[i][j]=k;} }return u; }int Look(int i,int j) //备忘录计算最优值{ if (m[i][j]>0){ return m[i][j]; }if (i == j) return 0;int u=Look(i, i)+Look(i+1,j)+p[i-1]*p[i]*p[j]; s[i][j]=i;for (int k=i+1; k<j;k++){ int t=Look(i,k)+Look(k+1,j)+p[i-1]*p[k]*p[j]; //递归if (t<u){ u=t; //从k处断开,分别求得每次的数乘次数s[i][j]=k; //返回t,k中较小的值,并记录断点处k} } m[i][j]=u;return u; }void Traceback(int i,int j) { //输出矩阵结合方式,加括号输出if(i == j) //只有一个矩阵,直接输出{ cout<<"A"<<i; }else if(i+1 == j) //两个矩阵,加括号输出{ cout<<"(A"<<i<<"A"<<j<<")"; }else{ cout<<"("; Traceback(i,s[i][j]); //递归,从最得到最优解的地方s[i][j]处断开Traceback(s[i][j]+1,j);cout<<")"; } }void main(){ cout<<"输入矩阵个数:n=";cin>>n; cout<<"输入第一个矩阵行数和第一个到第n个矩阵的列数:"; for(int i=0;i<=n;i++){ cin>>p[i]; } cout<<endl; cout<<"请选择解决矩阵连乘问题的方法:"<<endl; cout<<"1.动态规划算法"<<endl; cout<<"2.直接递归算法"<<endl; cout<<"3.备忘录算法"<<endl;cout<<"0.退出..."<<endl;cout<<endl;cout<<"请选择算法:";cin>>q; cout<<endl;while(q!=0){ switch(q){case 1: matrixChain(); cout<<"动态规划算法解决矩阵连乘问题:"<<endl; cout<<"最优计算次序为:";Traceback(1,n); cout<<endl; cout<<"矩阵连乘的最优数乘次数为:"<<m[1][n]<<endl; //最终解值为m[1][n]break;case 2: Recur(0,n); cout<<"直接递归算法解决矩阵连乘问题:"<<endl;5、结论动态规划算法设计通常有四个步骤:1.找出最优解的性质,并刻画其结构特征。
实验2 动态规划算法
{ return } private int weight; private int value; public WuPin(int weight, int value) { super(); this.weight = weight; this.value = value; } public int getValue() { return value; } public int getWeight() { return weight; } public int compareTo(Object o) { WuPin obj =(WuPin)o; return this.weight>obj.getWeight()?1:(this.weight==obj.getWeight()?0:-1); } } public class Beibao { public static void main(String[] args) { LinkedList<WuPin> wuPinList = new LinkedList<WuPin>(); wuPinList.add(new WuPin(2,6)); wuPinList.add(new WuPin(2,3)); wuPinList.add(new WuPin(6,5)); wuPinList.add(new WuPin(5,4)); wuPinList.add(new WuPin(4,6)); final int N = 6;//代表共有几个物品 LinkedList p = new LinkedList(); p.add(new WuPin(0,0));//添加第一个为零的值 for(int i =4;i>=0;i--) { weight + " " +value ;
矩阵连乘java实验报告
矩阵连乘java实验报告1. 实验目的本实验通过使用Java编程实现矩阵的连乘运算,旨在让学生理解矩阵的乘法规则以及动态规划的思想,并掌握使用动态规划算法解决问题的方法。
2. 实验原理2.1 矩阵乘法规则两个矩阵相乘的规则如下:设A为m行n列的矩阵,B为n行p列的矩阵,其乘积C为m行p列的矩阵。
C的第i行第j列元素可以通过以下公式计算得到:C\[i][j] = A\[i]\[1] \* B\[1]\[j] + A\[i]\[2] \* B\[2]\[j] + ... + A\[i]\[n] \*B\[n]\[j]2.2 动态规划算法对于矩阵乘法问题,使用动态规划算法可以有效地解决。
动态规划算法的基本思想是将一个大问题划分为多个子问题,并记忆子问题的解,以避免重复计算。
在矩阵连乘问题中,我们可以定义一个二维数组dp,其中dp\[i]\[j]表示从第i 个矩阵乘到第j个矩阵的最小乘法次数。
通过不断更新dp数组的值,最终可以得到整个矩阵连乘的最小乘法次数。
3. 实验步骤3.1 构建矩阵类首先,我们需要构建一个矩阵类Matrix,用于表示和操作矩阵。
Matrix类应包含以下成员变量和方法:- 成员变量:- int rows:矩阵的行数- int cols:矩阵的列数- int[][] data:矩阵的数据存储- 方法:- Matrix(int rows, int cols):构造函数,创建一个指定行数和列数的空矩阵- void setValue(int row, int col, int value):设置矩阵指定位置的值- int getValue(int row, int col):获取矩阵指定位置的值- int getRows():获取矩阵的行数- int getCols():获取矩阵的列数- static Matrix multiply(Matrix a, Matrix b):静态方法,用于计算两个矩阵的乘积3.2 实现矩阵连乘算法在主程序中,我们先创建一个Matrix类型的数组来保存需要连乘的矩阵。
动态规划算法分析与设计实验报告
算法分析与设计实验报告实验题目: 动态规划算法的设计与实现1、实验目的通过本实验,掌握动态规划算法的设计的基本思想,进一步提高学生的编程能力。
2、实验内容:给定n个矩阵{A1,A2,…,A n},其中A i与A i+1就是可乘的,i=1,2…,n-1。
如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
3、源程序if (t<u) //返回t,k中较小的值,并记录断点处k{ u=t; s[i][j]=k;} }return u; }int Look(int i,int j) //备忘录计算最优值{ if (m[i][j]>0){ return m[i][j]; }if (i == j) return 0;int u=Look(i, i)+Look(i+1,j)+p[i-1]*p[i]*p[j]; s[i][j]=i;for (int k=i+1; k<j;k++){ int t=Look(i,k)+Look(k+1,j)+p[i-1]*p[k]*p[j]; //递归if (t<u){ u=t; //从k处断开,分别求得每次的数乘次数s[i][j]=k; //返回t,k中较小的值,并记录断点处k} } m[i][j]=u;return u; }void Traceback(int i,int j) { //输出矩阵结合方式,加括号输出if(i == j) //只有一个矩阵,直接输出{ cout<<"A"<<i; }else if(i+1 == j) //两个矩阵,加括号输出{ cout<<"(A"<<i<<"A"<<j<<")"; }else{ cout<<"("; Traceback(i,s[i][j]); //递归,从最得到最优解的地方s[i][j]处断开Traceback(s[i][j]+1,j);cout<<")"; } }void main(){ cout<<"输入矩阵个数:n=";cin>>n; cout<<"输入第一个矩阵行数与第一个到第n个矩阵的列数:"; for(int i=0;i<=n;i++){ cin>>p[i]; } cout<<endl; cout<<"请选择解决矩阵连乘问题的方法:"<<endl; cout<<"1、动态规划算法"<<endl; cout<<"2、直接递归算法"<<endl; cout<<"3、备忘录算法"<<endl;cout<<"0、退出、、、"<<endl;cout<<endl;cout<<"请选择算法:";cin>>q; cout<<endl;while(q!=0){ switch(q){case 1: matrixChain(); cout<<"动态规划算法解决矩阵连乘问题:"<<endl; cout<<"最优计算次序为:";Traceback(1,n); cout<<endl; cout<<"矩阵连乘的最优数乘次数为:"<<m[1][n]<<endl; //最终解值为m[1][n]break;case 2: Recur(0,n); cout<<"直接递归算法解决矩阵连乘问题:"<<endl;cout<<"最优计算次序为:";Traceback(1,n);cout<<endl; cout<<"矩阵连乘的最优数乘次数为:"<<m[1][n]<<endl; //最终解值为m[1][n]break;case 3: Look(1,n); cout<<"备忘录算法解决矩阵连乘问题:"<<endl;cout<<"最优计算次序为:";Traceback(1,n);cout<<endl; cout<<"矩阵连乘的最优数乘次数为:"<<m[1][n]<<endl; //最终解值为m[1][n]break;case 0:q=0; break; }cout<<endl; cout<<"请选择解决矩阵连乘问题的方法:"<<endl; cout<<"1、动态规划算法"<<endl; cout<<"2、直接递归算法"<<endl; cout<<"3、备忘录算法"<<endl;cout<<"0、退出、、、"<<endl;cout<<"请选择算法:";cin>>q;cout<<endl; }cout<<endl; }5、结论动态规划算法设计通常有四个步骤:1.找出最优解的性质,并刻画其结构特征。
动态规划算法实验报告材料
实验标题1、矩阵连乘2、最长公共子序列3、最大子段和4、凸多边形最优三角剖分5、流水作业调度6、0-1背包问题7、最优二叉搜索树实验目的掌握动态规划法的基本思想和算法设计的基本步骤。
实验内容与源码1、矩阵连乘#include<iostream>#include<cstdlib>using namespace std;const int size=4;//ra,ca和rb,cb分别表示矩阵A和B的行数和列数void matriMultiply(int a[][4],int b[][4],int c[][4],int ra ,int ca,int rb ,int cb ){if(ca!=rb) cerr<<"矩阵不可乘";for(int i=0;i<ra;i++)for(int j=0;j<cb;j++){int sum=a[i][0]*b[0][j];for(int k=1;k<ca;k++)sum+=a[i][k]*b[k][j];c[i][j]=sum;}}void MatrixChain(int *p,int n,int m[][4],int s[][4]){for(int i=1;i<=n;i++) m[i][i]=0;//对角线for(int r=2;r<=n;r++)//外维for(int i=1;i<=n-r+1;i++)//上三角{int j=i+r-1;m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];s[i][j]=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];if(t<m[i][j]){m[i][j]=t;s[i][j]=k;}}}}void Traceback(int i,int j,int s[][4]){if(i == j){cout<<"A"<<i;}else if(i+1 == j){cout<<"(A"<<i<<"A"<<j<<")";}else{cout<<"(";Traceback(i,s[i][j],s);Traceback(s[i][j]+1,j,s);cout<<")";}}int main(){int w;cout<<"矩阵个数:";cin>>w;int p[w],s[w][w];cout<<"输入矩阵A1维数:";cin>>p[0]>>p[1];for(int i=2 ; i<=w ; i++){int m = p[i-1];cout<<"输入矩阵A"<<i<<"维数:";cin>>p[i-1]>>p[i];if(p[i-1] != m){cout<<endl<<"维数不对,矩阵不可乘!"<<endl; exit(1);}}Traceback(1,w,s);return 0;}运行结果2、最长公共子序列#include<cstring>#include<iostream>#define N 100using namespace std;//str1存储字符串x,str2存储字符串ychar str1[N],str2[N];//lcs存储最长公共子序列char lcs[N];//c[i][j]存储str1[1...i]与str2[1...j]的最长公共子序列的长度int c[N][N];//flag[i][j]==0为str1[i]==str2[j]//flag[i][j]==1为c[i-1][j]>=s[i][j-1]//flag[i][j]==-1为c[i-1][j]<s[i][j-1]int flag[N][N];//求长度int LCSLength(char *x, char *y){int i,j;//分别取得x,y的长度int m = strlen(x);int n = strlen(y);for(i=1;i<=m;i++)c[i][0] = 0;for(i=0;i<=n;i++)c[0][i] = 0;for(i=1;i<=m;i++)for(j=1;j<=n;j++){if(x[i-1]==y[j-1]){c[i][j] = c[i-1][j-1] +1;flag[i][j] = 0;}else if(c[i-1][j]>=c[i][j-1]){c[i][j] = c[i-1][j];flag[i][j] = 1;}else{c[i][j] = c[i][j-1];flag[i][j] = -1;}}return c[m][n];}//求出最长公共子序列char* getLCS(char *x, char *y,int len,char *lcs) {int i = strlen(x);int j = strlen(y);while(i&&j){if(flag[i][j]==0){lcs[--len] = x[i-1];i--;j--;}else if(flag[i][j]==1)i--;elsej--;}return lcs;}int main(){int i;cout<<"请输入字符串x:"<<endl;cin>>str1;cout<<"请输入字符串y:"<<endl;cin>>str2;int lcsLen = LCSLength(str1,str2);cout<<"最长公共子序列长度:"<<lcsLen<<endl; char *p = getLCS(str1,str2,lcsLen,lcs);cout<<"最长公共子序列为:";for(i=0;i<lcsLen;i++)cout<<lcs[i]<<" ";return 0;}运行结果3、最大子段和//分治法求最大子段和#include<iostream>using namespace std;int MaxSubSum(int *a,int left,int right){int sum=0;if(left==right) sum=a[left]>0?a[left]:0;else{int center = (left+right)/2;//最大子段和在左边int leftsum=MaxSubSum(a,left,center);//最大子段和在右边int rightsum=MaxSubSum(a,center+1,right);//最大子段和在中间int s1=0;int lefts=0;for(int i=center;i>=left;i--){lefts+=a[i];if(lefts>s1) s1=lefts;}int s2=0;int rights=0;for(int i=center+1;i<=right;i++) {rights+=a[i];if(rights>s2) s2=rights;}sum=s1+s2;//前后子段和相加//判断最大子段和if(sum>leftsum)sum=leftsum;if(sum>rightsum) sum=rightsum; }return sum;}int MaxSum(int *a,int n){return MaxSubSum(a,1,n-1);}int main(){int a[8]={2,-3,-5,4,1,7,1,-5};cout<<"最大子段和为:"<<MaxSum(a,8); return 0;}//动态规划法#include<iostream>using namespace std;int MaxSum(int *a,int n){int sum=0,b=0;for(int i=1;i<n;i++)//此处不能=n,{if(b>0) b+=a[i];else b=a[i];if(b>sum) sum=b;}return sum;}int main(){int a[8]={2,-3,-5,4,1,7,1,-5};cout<<"最大子段和为:"<<MaxSum(a,8);return 0;}运行结果4、凸多边形最优三角剖分#include<iostream>#include<cmath>#include<cstdlib>#define N 50using namespace std;struct point{int x;int y;};int distance(point X, point Y)//两点距离{int dis = (Y.x-X.x)*(Y.x-X.x) + (Y.y-X.y)*(Y.y-X.y);return (int)sqrt(dis);}int w(point a, point b, point c)//权值{return distance(a,b) + distance(b,c) + distance(a,c); }bool JudgeInput()//判断是否能构成凸多边形{point *v; //记录凸多边形各顶点坐标int *total; //记录坐标在直线方程中的值 int m,a,b,c;cout<<"请输入凸多边形顶点个数:";cin>>m;int M = m-1;for(int i=0 ; i<m ; i++){cout<<"输入顶点v"<<i<<"的坐标:";cin>>v[i].x>>v[i].y;}//根据顶点坐标判断是否能构成一个凸多边形for(int j=0 ; j<m ; j++){int p = 0;int q = 0;if(m-1 == j){a = v[m-1].y - v[0].y;b = v[m-1].x - v[0].y;c = b * v[m-1].y - a * v[m-1].x;}else{a = v[j].y - v[j+1].y;b = v[j].x - v[j+1].x;c = b * v[j].y - a * v[j].x;}for(int k=0 ; k<m ; k++){total[k] = a * v[k].x - b * v[k].y + c; if(total[k] > 0){p = p+1;}else if(total[k] < 0){q = q+1;}}if((p>0 && q>0) || (p==0 && q==0)){cout<<"无法构成凸多边形!"<<endl;exit(1);}}}bool minWeightTriangulation()//计算最优值算法{int M;int **t, **s;point *v;for(int i=1 ; i<=M ; i++)t[i][i] = 0;for(int r=2 ; r<=M ; r++)for(int i=1 ; i<=M-r+1 ; i++){int j = i+r-1;t[i][j] = t[i+1][j] + w(v[i-1],v[i],v[j]);s[i][j] = i;for(int k=i+1 ; k<i+r-1 ; k++){int u = t[i][k] + t[k+1][j] + w(v[i-1],v[k],v[j]); if(u < t[i][j]){t[i][j] = u;s[i][j] = k;}}}return true;}void Traceback(int i, int j, int **s){if(i == j)return;Traceback(i,s[i][j],s);Traceback(s[i][j]+1,j,s);cout<<"三角形:v"<<i-1<<"v"<<s[i][j]<<"v"<<j<<endl;}int main(){int **s; //记录最优三角剖分中所有三角形信息 int **t; //记录最优三角剖分所对应的权函数值 point *v; //记录凸多边形各顶点坐标int *total; //记录坐标在直线方程中的值int M=0;t = new int *[N];s = new int *[N];for(int i=0 ; i<N ; i++){t[i] = new int[N];s[i] = new int[N];}v = new point[N];total = new int[N];if(JudgeInput()){if(minWeightTriangulation()){Traceback(1,M,s);cout<<endl;cout<<"最优权值之和为:"<<t[1][M]<<endl; }}return 0;}运行结果:5、流水作业调度#include<iostream>#define N 100using namespace std;class Jobtype{public:/* int operator<=(Jobtype a)const{return(key<=a.key);}*/int key;int index;bool job;};void sort(Jobtype *d,int n){int i,j;Jobtype temp;bool exchange; //交换标志for(i = 0;i < n;i ++){ //最多做n-1趟排序exchange = false; //本趟排序开始前,交换标志应为假for(j = n - 1;j >= i;j --)if(d[j+1].key < d[j].key){temp = d[j+1];d[j+1] = d[j];d[j] = temp;exchange=true; //发生了交换,故将交换标志置为真 }if(!exchange) //本趟排序未发生交换,提前终止算法 return;}}int FlowShop(int n,int *a,int *b,int *c){Jobtype *d = new Jobtype[n];for(int i=0;i<n;i++)//初始化{d[i].key=a[i]>b[i]?b[i]:a[i];// 执行时间d[i].job=a[i]<=b[i];// 作业组d[i].index=i;//作业序号}sort(d,n);;int j=0;int k=n-1;for(int i=0;i<n;i++)//最优调度{if(d[i].job){c[j++]=d[i].index;}else{c[k--]=d[i].index;}}j=a[c[0]];k=j+b[c[0]];for(int i=1;i<n;i++){j+=a[c[i]];k=j<k?k+b[c[i]]:j+b[c[i]];}delete d;//回收空间return k;//返回调度时间}int main(){int n,*a,*b,*c;cout<<"作业数:";cin>>n;Jobtype *d = new Jobtype[N];a=new int[N];b=new int[N];c=new int[N];cout<<"请输入作业号和时间:";for(int i=0;i<n;i++){cin>>d[i].index>>d[i].key;}cout << endl;int k=FlowShop(n,a,b,c);cout<<"\n调度时间:"<<k<<endl;cout<<"最优调度序列:";for (int i = 0; i < n; i++) // 输出最优调度序列 {cout << c[i] << " ";}return 0;}运行结果:6、0-1背包问题#include <iostream>#include <iomanip>using namespace std;const int C=10;//容量const int N=5;//个数int max(const int a,const int b){return a>b?a:b;}int min(const int a,const int b){return a<b?a:b;}/*m为记录数组 m[i][j]代表在剩有j容量的条件下,从i开始往后的物品中可以取得的最大价值w为重量数组,v为价值数组n为物品个数,c为开始容量则m[1][c]即此背包能剩下的最大价值*/void knapsack(int **m,int n, int c,int *w, int *v){int jMax = min(w[n]-1,c);//前n-1个物品for(int j=0;j<=jMax;j++)m[n][j]=0;for(int j=w[n];j<=c;j++)m[n][j]=v[n];for(int i=n-1;i>1;i--){jMax=min(w[i]-1,c);for(int j=0;j<=jMax;j++)m[i][j] = m[i+1][j];for(int j=w[i];j<=c;j++)m[i][j] = max(m[i+1][j],m[i+1][j-w[i]]+v[i]); }m[1][c]=m[2][c];if(c>=w[1])m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);}//找出最优解,0表示不能装,1表示能装void traceback(int **m,int n,int c,int *x,int *w){for(int i=1;i<n;i++){if(m[i][c]==m[i+1][c]) x[i]=0;else{x[i]=1;c-=w[i];}}x[n]=(m[n][c]==0)?0:1;}int main(){int *v=new int[N+1];int *w=new int[N+1];int **m=new int* [N+1];int *x=new int [N+1];for(int i=0;i<N+1;i++){m[i]=new int[C+1];}cout<<"输入重量序列,"<<N<<"个"<<endl;for(int i=1;i<=N;i++)cin>>w[i];cout<<"输入价值序列,"<<N<<"个"<<endl;for(int i=1;i<=N;i++)cin>>v[i];knapsack(m,N,C,w,v);traceback(m,N,C,x,w);cout<<"最优值:"<<m[1][C]<<endl;cout<<"是否装入背包的情况:";for(int i=1;i<=N;i++){cout<<x[i];}for(int i=0;i<N+1;i++){delete m[i];}delete []m;return 0;}运行结果7、最优二叉搜索树#include<iostream>#include<cmath>#include<limits>#define N 100using namespace std;const double MAX = numeric_limits<double>::max(); //double的最大值//a[i]为结点i被访问的概率//b[i]为“虚结点”i被访问的概率//m[i][j]用来存放子树(i,j)的期望代价//w[i][j]用来存放子树(i,j)的所有结点(包括虚结点)的a,b概率之和//s[i][j]用来跟踪root的void OptimalBinarySearchTree(double *a,double *b,int n){int s[N][N];double m[N][N];double w[N][N];int i,j,l,r;for(i=1; i<=n+1; i++){m[i][i-1] = b[i-1];w[i][i-1] = b[i-1];}for(l=1; l<=n; l++){for(i=1; i<=n-l+1; i++){j = l+i-1;m[i][j] = MAX;w[i][j] = w[i][j-1] + a[j] +b[j];for(r=i; r<=j; r++){double k = m[i][r-1] + w[i][j] + m[r+1][j]; if(k<m[i][j]){m[i][j] = k;s[i][j] = k;}}}}cout<<m[1][n];}int main(){double a[N],b[N];int n;double sum = 0;int i,j,l;cout<<"请输入关键字的个数:"<<endl;cin>>n;cout<<"请输入每个关键字的概率:"<<endl;for(i=1; i<=n; i++){cin>>a[i];sum += a[i];}cout<<"请输入每个虚拟键的概率:"<<endl;for(i=0; i<=n; i++){cin>>b[i];sum += b[i];}if(abs(sum-1)>0.01){cout<<"输入的概率和不为1,请重新输入"<<endl;}cout<<"最优二叉查找树的期望搜索代价为:";OptimalBinarySearchTree(a,b,n);return 0;}运行结果:实验总结通过实现动态规划的这个题目,对动态规划算法有了进一步的了解。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法分析与设计实验报告
实验题目:动态规划算法的设计与实现
1、实验目的
通过本实验,掌握动态规划算法的设计的基本思想,进一步提高学生的编程能力。
2、实验内容:
给定n个矩阵{A1,A2,…,A n},其中A i与A i+1是可乘的,i=1,2…,n-1。
如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
3、源程序
if (t<u) //返回t,k中较小的值,并记录断点处k
{ u=t; s[i][j]=k;
} }
return u; }
int Look(int i,int j) //备忘录计算最优值
{ if (m[i][j]>0)
{ return m[i][j]; }
if (i == j) return 0;
int u=Look(i, i)+Look(i+1,j)+p[i-1]*p[i]*p[j]; s[i][j]=i;
for (int k=i+1; k<j;k++)
{ int t=Look(i,k)+Look(k+1,j)+p[i-1]*p[k]*p[j]; //递归
if (t<u)
{ u=t; //从k处断开,分别求得每次的数乘次数s[i][j]=k; //返回t,k中较小的值,并记录断点处k
} } m[i][j]=u;
return u; }
void Traceback(int i,int j) { //输出矩阵结合方式,加括号输出
if(i == j) //只有一个矩阵,直接输出
{ cout<<"A"<<i; }
else if(i+1 == j) //两个矩阵,加括号输出
{ cout<<"(A"<<i<<"A"<<j<<")"; }
else
{ cout<<"("; Traceback(i,s[i][j]); //递归,从最得到最优解的地方s[i][j]处断开Traceback(s[i][j]+1,j);
cout<<")"; } }
void main()
{ cout<<"输入矩阵个数:n=";
cin>>n; cout<<"输入第一个矩阵行数和第一个到第n个矩阵的列数:"; for(int i=0;i<=n;i++)
{ cin>>p[i]; } cout<<endl; cout<<"请选择解决矩阵连乘问题的方法:"<<endl; cout<<"1.动态规划算法"<<endl; cout<<"2.直接递归算法"<<endl; cout<<"3.备忘录算法"<<endl;
cout<<"0.退出..."<<endl;
cout<<endl;
cout<<"请选择算法:";
cin>>q; cout<<endl;
while(q!=0){ switch(q){
case 1: matrixChain(); cout<<"动态规划算法解决矩阵连乘问题:"<<endl; cout<<"最优计算次序为:";
Traceback(1,n); cout<<endl; cout<<"矩阵连乘的最优数乘次数为:
"<<m[1][n]<<endl; //最终解值为m[1][n]
break;
case 2: Recur(0,n); cout<<"直接递归算法解决矩阵连乘问题:"<<endl;
5、结论
动态规划算法设计通常有四个步骤:
1.找出最优解的性质,并刻画其结构特征。
2.递归的定义最优解
3.自底向上的方式计算出最优值。
4.根据计算最优值时得到的信息,构造最优解。