一、实验目的: 理解动态规划算法的基本思想和设计步骤; 掌握动态规划算法的典型应用范例——矩阵连乘。 | ||||||||
二、实验内容 矩阵连乘 给定n个可乘的数字矩阵A1,…,An,以及矩阵的阶p0* p1, p1* p2,…, pn-1* pn,求给定矩阵链的最优计算次序使得所需要的数乘次数最少。 例如,求以下6个矩阵连乘积的最少数乘计算次数及所采用的乘法次序。 A1:30*35;A2:35*15;A3:15*5;A4:5*10;A5:10*20;A6:20*25. 程序代码: #include<stdio.h> #include<string.h> #define N 100 long C(int mn); int dim[N]; long M[N][N]; int Bestk[N][N]; void Tback(int Bestk[N][N],int i,int j); long C(int mn){ int i,j,len,k; for(i=1;i<=mn;i++) M[i][i]=0; for(len=2;len<=mn;len++){ for(i=1;i<=mn-len+1;i++){ j=i+len-1; M[i][j]=M[i+1][j]+dim[i-1]*dim[i]*dim[j]; Bestk[i][j]=i; for(k=i+1;k<j;k++){ long ans=M[i][k]+M[k+1][j]+dim[i-1]*dim[k]*dim[j]; if(ans<M[i][j]){ Bestk[i][j]=k; M[i][j]=ans; }}}} return M[1][mn];} void Tback(int Bestk[][N],int i,int j){ if (i==j) return; Tback(Bestk,i,Bestk[i][j]); Tback(Bestk,Bestk[i][j]+1,j); printf("A%d 和 A%d\n",i,j); } void main() {
int i,mn; printf("请输入相乘矩阵的个数:\n"); scanf("%d",&mn); printf("请输入每个矩阵的行数和列数,相邻矩阵只输入一次即可\n"); while(EOF !=mn){ for(i=0;i<=mn;i++) scanf("%d",&dim[i]); printf("最优的连乘次数为:\n"); printf("%ld\n",C(mn)); printf("其中具体最优的连乘次序为:\n"); Tback(Bestk,1,mn); }} 程序测试及运行结果: | ||||||||
分析与讨论:
我的思路是首先我们知道矩阵连乘的条件:第一个矩阵的列等于第二个矩阵的行,此时两个矩阵是可乘的,并且我们知道多个矩阵连乘的结果矩阵,其行列等于第一个矩阵的行和最后一个矩阵的列。所以先定义一个数组来保存它们的行和列数,以题目所给矩阵为例子。A1:30*35;A2:35*15;A3:15*5;A4:5*10;A5:10*20;A6:20*25.,那么定义一个数组为p={30,35,15,5,10,20,25}那么p[0],p[1]代表第一个矩阵的行数和列数,p[1],p[2]代表第二个矩阵的行数和列数…p[5],p[6]代表第六个矩阵的行数和列数。首先对数据进行初始化,然后通过不同的括号划分来对矩阵进行不同的连乘,通过自底向上的方法求得M(i,j)。
优点: 能够得到全局最优解;动态规划模型的缺点: 缺点:数值方法求解时存在维数灾并且没有统一的标准模型; 总结:当一个问题能够划分成n个相互独立的子问题的时候我们常用分治法来解决,但是当这些子问题不全相互独立的时候再用分治法就会多次重复计算子问题,造成资源的浪费,这个时候就用动态规划法,就是要划分出各种子问题,这些子问题的求法和原问题一模一样,我们可以直接利用求解好的子问题对原问题进行求最优 |