收藏 分销(赏)

动态规划算法实验报告.doc

上传人:仙人****88 文档编号:9312287 上传时间:2025-03-21 格式:DOC 页数:17 大小:277.04KB 下载积分:10 金币
下载 相关 举报
动态规划算法实验报告.doc_第1页
第1页 / 共17页
动态规划算法实验报告.doc_第2页
第2页 / 共17页


点击查看更多>>
资源描述
实验标题 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 100 using namespace std; //str1存储字符串x,str2存储字符串y char 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--; else j--; } 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 50 using 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 100 using 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 100 using 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; } 运行结果: 实验总结 通过实现动态规划的这个题目,对动态规划算法有了进一步的了解。先分析问题,判断是否具有最优子结果和重叠字问题的性质。
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 教育专区 > 小学其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服