浙江工业大学算法实验2 动态规划算法实现

合集下载

动态规划算法的实现及其应用

动态规划算法的实现及其应用

动态规划算法的实现及其应用动态规划,英文缩写为 DP,是一种算法设计技术,通常用于求解最优化问题。

动态规划是解决一类特殊问题的有效方法。

它通过将原问题转化为若干个子问题的方式,逐个求解这些子问题,最终得到原问题的解。

这种方式具有很强的适用性,能够解决很多实际问题。

动态规划的实现动态规划算法的实现基本上可以分为以下两个步骤:1. 确定状态:将原问题转化为若干个子问题,定义合适的状态量来表示子问题。

状态的定义应该满足无后效性,即状态一旦确定,之后的状态转移不会再受之前的状态影响。

2. 确定状态转移方程:定义状态转移方程,通过状态之间的转移来逐步求解原问题。

状态转移方程可以通过一些简单的规律得到,也可以通过数学方法进行求解。

动态规划的应用动态规划算法有很多应用,下面列举一些常见的应用场景。

1. 最长公共子序列问题:给定两个字符串,求出它们的最长公共子序列,即在两个字符串中都出现的、长度最长的子序列。

这个问题可以用动态规划算法求解,状态可以定义为在两个字符串的某段位置上的最长公共子序列的长度,状态转移方程比较简单。

2. 背包问题:有一个容量为 V 的背包和 n 种物品,每种物品的重量为 wi,价值为 vi,现在要用这些物品装满背包,使得背包中所装物品的总价值最大。

这个问题可以用动态规划算法求解,状态可以定义为在前 i 件物品中,体积为 j 的情况下能获得的最大价值,状态转移方程也比较简单。

3. 最短路问题:给定一个带权图,求出其中从起点到终点的最短路径。

这个问题可以用动态规划算法求解,状态可以定义为从起点到某个点的最短路径,状态转移方程可以通过分阶段来进行求解。

4. 求解最大子段和问题:给定一个序列,求出其中连续子段的和的最大值。

这个问题也可以用动态规划算法求解,状态可以定义为以某个位置为结尾的最大子段和,状态转移方程与之前的问题类似。

动态规划算法虽然能够解决很多问题,但是它也存在一些限制。

动态规划算法的计算复杂度较高,需要占用大量的内存空间。

浙江工业大学算法实验2 动态规划算法实现

浙江工业大学算法实验2  动态规划算法实现

实验2 动态规划算法实现一、实验目标:1.熟悉动态规划算法实现的基本方法和步骤;2. 学会动态规划算法的实现方法和分析方法:二、实验内容:问题1:最长公共子序列的问题,测试数据X={ABCBDAB} Y={BDCABA}X={zhejiang university of technology} Y= {zhejiang university city college}1-1实验代码及截图#include<iostream>#include<cstring>using namespace std;//求得两个字符串的最大公共子序列长度int LCSLength(int m, int n,char* x, char* y,int **c, int **b){int i, j, len;//i=0 || j=0for (i = 0; i < m + 1; i++) c[i][0] = 0;for (j = 0; j < n + 1; j++) c[0][j] = 0;//i,j>0for (i = 1; i <= m; i++){for (j = 1; j <= n; j++){if (x[i] == y[j])//if (x[i - 1] == y[j - 1]){c[i][j] = c[i - 1][j - 1] + 1;b[i][j] = 1;}else if (c[i - 1][j] >= c[i][j - 1]){c[i][j] = c[i - 1][j];b[i][j] = 2;}else{c[i][j] = c[i][j - 1];b[i][j] = 3;}}}len = c[m][n];return len;}//构造最长公共子序列void LCS(int i, int j, char *x, int **b){if (i == 0 || j == 0) return;if (b[i][j] == 1){LCS(i - 1, j - 1, x, b);cout << x[i - 1];//c[i][]对应str1的第i-1个元素}else if (b[i][j] == 2){LCS(i - 1, j, x, b);}else{LCS(i, j - 1, x, b);}}int main(){char str1[1000], str2[1000];int i, m, n, len;cout << "请输入第一个字符串:";gets_s(str1);cout << "请输入第二个字符串:";gets_s(str2);m = strlen(str1);n = strlen(str2);int **c = new int*[m + 1]; //行for (i = 0; i < m + 1; i++)c[i] = new int[n + 1];//列int **b = new int*[m + 1];for (i = 0; i < m + 1; i++)b[i] = new int[n + 1];len = LCSLength(m, n, str1, str2, c, b);cout << "最长公共子序列的长度为:" << len << endl;cout << ("最长公共子序列为:");LCS(m, n, str1, b);cout << endl;system("pause");return 0;}实验截图:1-2实验总结:实验最开始考虑到穷举,但很明显时间复杂度过于庞大,利用最长公共子序列的最优子结构性质,结合书上代码进行实验,但实验中很明显没有考虑多种最长公共子序列的情况,这个可能要留待后续继续学习改进。

动态规划算法原理和实现

动态规划算法原理和实现

动态规划算法原理和实现动态规划是解决某些优化问题的一种算法思想,它主要针对的是那些可以分解成子问题的大问题,因此也被称作分治法。

动态规划算法的核心思想是将大问题分解成一个个小问题,然后逐步求解这些小问题并将它们组合成原问题的解。

本文将简单介绍动态规划算法的原理和实现。

一、动态规划算法的原理为了更好地理解动态规划算法的原理,我们可以以一个实例为例:假设有一个背包,它最多能装W重量的物品,现在有n种不同的物品,每种物品都有自己的重量w和价值v。

我们需要选择哪些物品放入背包中,以使得背包中物品的总价值最大。

这是一个典型的动态规划问题。

首先,我们可以把问题分解成子问题:设f(i,j)表示前i种物品放入一个容量为j的背包可以获得的最大价值。

因此,我们可以得到以下状态方程式:f(i,j) = max{f(i-1,j), f(i-1,j-w[i])+v[i]} (1≤i≤n,1≤j≤W)其中,f(i-1,j)表示不放第i种物品的最大价值,f(i-1,j-w[i])+v[i]表示放入第i种物品的最大价值。

因此,当我们计算出f(i,j)时,我们就得到了「前i种物品放入容量为j的背包的最大价值」,这也就是原问题的解。

这样,我们就可以使用动态规划算法来计算出最优解。

具体来说,我们从0开始,逐个计算出f(i,j)的值,直到计算出f(n,W)为止。

此外,我们还需要注意以下几点:1. 在计算f(i,j)的时候,我们需要使用到f(i-1,j)和f(i-1,j-w[i])这两个状态,因此我们需要先计算出f(1,j),在此基础上计算f(2,j),以此类推。

2. 对于一些特殊的情况,我们需要单独处理。

比如当背包容量小于某种物品重量时,我们就无法放入该物品。

3. 我们在计算f(i,j)时,有许多状态是可以复用的。

比如,当我们计算出f(i-1,j)后,我们就可以直接使用这个值来计算f(i,j),而无需重新计算。

二、动态规划算法的实现上面我们已经介绍了动态规划算法的核心思想和实现原理,下面我们来看看具体的实现过程。

算法设计与分析实验2

算法设计与分析实验2

算法设计与分析实验21. 实验背景算法设计与分析是计算机科学中重要的研究方向,涉及到算法的设计、分析和实现。

本次实验旨在帮助学生进一步理解和掌握常见的算法设计与分析方法,通过实践操作加深对算法原理的理解。

2. 实验目的本次实验的主要目的如下:- 理解动态规划算法设计思想;- 学习并掌握动态规划算法的实现方法; - 熟悉动态规划算法的时间复杂度分析方法。

3. 实验内容本次实验的主要内容是实现一个动态规划算法,并分析它的时间复杂度。

3.1 动态规划算法介绍动态规划算法是一种将问题分解成子问题并逐个求解的方法。

它通过存储子问题的解来避免重复计算,从而提高算法的效率。

动态规划算法通常采用自底向上的方式来求解问题,即先求解小规模的子问题,再逐步扩大规模,直到解决原始问题。

3.2 实现一个动态规划算法在本次实验中,我们将实现一个动态规划算法来解决一个具体的问题。

具体步骤如下: 1. 确定子问题:将原问题分解为子问题; 2. 确定状态转移方程:定义一个状态转移方程,用于表示子问题与原问题之间的关系; 3. 确定边界条件:确定子问题的边界条件,即最简单的情况下的解; 4. 自底向上求解:根据状态转移方程和边界条件,逐步求解子问题,最终得到原问题的解。

3.3 时间复杂度分析完成动态规划算法的实现后,我们需要对算法的时间复杂度进行分析。

时间复杂度是衡量算法性能的重要指标,它反映了算法在处理输入规模增大时所需的时间。

在分析时间复杂度时,我们需要考虑算法的基本操作次数,并且基于不同输入规模的情况,推导出算法的大O表示法。

4. 实验结果完成实验后,我们得到了动态规划算法的实现代码,并对其进行了时间复杂度分析。

下面是实验结果的总结: - 实现了动态规划算法,并成功解决了一个具体的问题; - 分析了实现代码的时间复杂度,并得出了算法的大O表示法。

5. 总结与展望本次实验通过实现动态规划算法,深入了解了动态规划的设计与分析方法。

实验二 动态规划算法

实验二 动态规划算法

实验二动态规划算法一、实验目的与要求1、熟悉最长公共子序列问题的算法;2、初步掌握动态规划算法;二、实验题若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。

例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。

给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z 是序列X和Y的公共子序列。

给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。

三.(1)实验源代码://最长公共子序问题://问题描述: 若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},//是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。

//例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。

//给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z 是序列X和Y的公共子序列。

//给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。

#include<bits/stdc++.h>using namespace std;#define max 1000//注意:这里使用的char数组,可以按字符输出,若改为string类型,//执行printf("%c",A[m-1])就会报错;char A[100],B[100]; //输入的两个串a和b//这里定义全局变量可以不赋值0,因为全局变量自动赋值0;int c[max][max]; //记录最长公共子序的长度;int b[max][max]; //记录状态号;void LCS(int m,int n){if(m==0||n==0){return;else if(b[m][n]==1){LCS(m-1,n-1);printf("%c",A[m-1]);}else if(b[m][n]==2){m=m-1;LCS(m,n);}else if(b[m][n]==3){n=n-1;LCS(m,n);}}void LCS_length(int m,int n){for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){if(A[i-1]==B[j-1]){c[i][j]=c[i-1][j-1]+1;b[i][j]=1;}else if(c[i-1][j]>=c[i][j-1]){c[i][j]=c[i-1][j];b[i][j]=2;}else{c[i][j]=c[i][j-1];b[i][j]=3;}}}}{printf("请输入两个待测的字符串:\n");scanf("%s",&A);scanf("%s",&B);int m=strlen(A); //m为A串长度;int n=strlen(B); //n为B串长度;LCS_length(m,n);printf("其最长公共子序的长度为:%d\n",c[m][n]);printf("其最长公共子序为:");LCS(m,n);return 0;}(2)运行结果为:(3)算法思路:最长公共子序列的结构有如下表示:设序列X=<x1, x2, …, x m>和Y=<y1, y2, …, y n>的一个最长公共子序列Z=<z1, z2, …, z k>,则:1.若x m=y n,则z k=x m=y n且Z k-1是X m-1和Y n-1的最长公共子序列;2.若x m≠y n且z k≠x m ,则Z是X m-1和Y的最长公共子序列;3.若x m≠y n且z k≠y n,则Z是X和Y n-1的最长公共子序列。

动态规划问题实验报告(3篇)

动态规划问题实验报告(3篇)

第1篇一、实验目的本次实验旨在让学生理解动态规划算法的基本概念,掌握动态规划解决问题的基本思想和步骤,并能运用动态规划算法解决实际问题。

通过实验,学生应能够:1. 理解动态规划算法的概念及其应用领域。

2. 掌握动态规划的基本思想和解决问题的基本步骤。

3. 学习动态规划算法设计策略,并能够运用到实际问题中。

4. 通过实际编程,提高编程能力和问题解决能力。

二、实验环境1. 操作系统:Windows 102. 编程语言:Python3.83. 开发环境:PyCharm三、实验内容本次实验选择了三个典型的动态规划问题进行实践:1. 最长公共子序列问题2. 矩阵连乘问题3. 剪绳子问题四、实验步骤1. 最长公共子序列问题(1)问题描述:给定两个序列X和Y,找出X和Y的最长公共子序列。

(2)算法设计:- 使用二维数组dp[i][j]表示X的前i个字符和Y的前j个字符的最长公共子序列的长度。

- 初始化dp[0][j] = 0和dp[i][0] = 0。

- 对于i > 0和j > 0,如果X[i-1] == Y[j-1],则dp[i][j] = dp[i-1][j-1] + 1;否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1])。

(3)代码实现:```pythondef longest_common_subsequence(X, Y):m, n = len(X), len(Y)dp = [[0] (n + 1) for _ in range(m + 1)]for i in range(1, m + 1):for j in range(1, n + 1):if X[i - 1] == Y[j - 1]:dp[i][j] = dp[i - 1][j - 1] + 1else:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])return dp[m][n]```2. 矩阵连乘问题(1)问题描述:给定n个矩阵A1, A2, ..., An,其中Ai与Ai-1是可乘的,i = 1, 2, ..., n-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,intm[][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++){intt=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存储字符串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--;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;//最大子段和在左边intleftsum=MaxSubSum(a,left,center);//最大子段和在右边intrightsum=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篇)

第1篇本实验报告针对动态规划算法进行深入研究和实践,旨在通过一系列实验,加深对动态规划思想、基本原理及实际应用的理解。

实验内容涵盖了动态规划算法的多个经典问题,包括找零钱问题、独立任务最优调度问题、最长公共子序列问题、矩阵连乘问题、剪绳子问题以及0-1背包问题等。

一、实验目的1. 理解动态规划算法的概念,掌握动态规划的基本思想和解决问题的基本步骤。

2. 学习动态规划算法设计策略,提高算法设计能力。

3. 通过实际案例,体会动态规划算法在解决实际问题中的应用价值。

二、实验内容与步骤1. 找零钱问题实验要求设计一个动态规划算法,对给定面值的硬币组合,计算出所有可能找零方式的硬币个数。

通过实验,掌握了动态规划算法的基本原理,并熟悉了动态规划在解决组合优化问题中的应用。

2. 独立任务最优调度问题实验要求设计一个动态规划算法,使得两台处理机处理完n个作业的时间最短。

通过实验,了解了动态规划在解决调度问题中的应用,并掌握了多阶段决策问题的求解方法。

3. 最长公共子序列问题实验要求找出两个序列的最长公共子序列。

通过实验,学习了动态规划在解决序列匹配问题中的应用,并掌握了如何通过动态规划算法优化问题求解过程。

4. 矩阵连乘问题实验要求确定计算矩阵连乘积的计算次序,使得所需数乘次数最少。

通过实验,了解了动态规划在解决矩阵连乘问题中的应用,并掌握了如何通过动态规划算法优化计算过程。

5. 剪绳子问题实验要求将一根绳子剪成m段,使得各段乘积最大。

通过实验,掌握了动态规划在解决资源分配问题中的应用,并学会了如何通过动态规划算法找到最优解。

6. 0-1背包问题实验要求用动态规划算法解决0-1背包问题。

通过实验,了解了动态规划在解决背包问题中的应用,并掌握了如何通过动态规划算法优化问题求解过程。

三、实验结果与分析通过对以上问题的动态规划算法实现,实验结果表明:1. 动态规划算法能够有效地解决组合优化问题、调度问题、序列匹配问题、矩阵连乘问题、资源分配问题以及背包问题等。

动态规划算法的实施步骤

动态规划算法的实施步骤1. 算法介绍动态规划是一种常用的求解最优化问题的方法,它适用于求解具有重叠子问题特性的问题。

动态规划算法通过将问题拆分成小问题,并保存这些小问题的解来减少重复计算,从而提高求解效率。

2. 实施步骤步骤一:定义问题的状态在动态规划算法中,第一步是定义问题的状态。

问题的状态是指问题的子问题中需要求解的变量或指标。

这些状态一般可以用一个或多个变量来表示。

步骤二:确定状态转移方程确定状态转移方程是动态规划算法的核心步骤。

状态转移方程可以根据问题的特点和定义的状态来确定。

状态转移方程描述了问题的当前状态和下一个状态之间的关系。

步骤三:确定初始状态初始状态是指问题的最小规模的子问题的解,也就是边界条件。

初始状态的确定需要根据具体问题来定义。

步骤四:计算最优解根据定义的状态转移方程和初始状态,可以通过自底向上(bottom-up)或自顶向下(top-down)的方式,计算出问题的最优解。

步骤五:返回最优解最后一步是返回计算得到的最优解。

根据问题的特点和需求,最优解可以是一个值,也可以是一组值。

3. 实施示例为了更好地理解动态规划算法的实施步骤,下面以求解斐波那契数列为例进行说明。

步骤一:定义问题的状态在求解斐波那契数列的问题中,状态可以定义为第n个斐波那契数F(n)。

步骤二:确定状态转移方程斐波那契数列的状态转移方程为F(n) = F(n-1) + F(n-2)。

步骤三:确定初始状态斐波那契数列的初始状态可以定义为F(0) = 0,F(1) = 1。

步骤四:计算最优解根据状态转移方程和初始状态,可以通过自底向上的方式计算斐波那契数列的最优解。

def fibonacci(n):if n ==0:return0elif n ==1:return1else:dp = [0] * (n+1)dp[0] =0dp[1] =1for i in range(2, n+1):dp[i] = dp[i-1] + dp[i-2]return dp[n]步骤五:返回最优解在上述示例中,最优解为fibonacci(n),即第n个斐波那契数。

动态规划算法的应用实验报告

实验二动态规划算法的应用一、实验目的1.掌握动态规划算法的基本思想,包括最优子结构性质和基于表格的最优值计算方法。

2.熟练掌握分阶段的和递推的最优子结构分析方法。

3.学会利用动态规划算法解决实际问题。

二、实验内容1.问题描述:题目一:数塔问题给定一个数塔,其存储形式为如下所示的下三角矩阵。

在此数塔中,从顶部出发,在每一节点可以选择向下走还是向右走,一直走到底层。

请找出一条路径,使路径上的数值和最大。

输入样例(数塔):912 1510 6 82 18 9 519 7 10 4 16输出样例(最大路径和):59三、算法设计void main(){申明一个5*5的二维数组;for(int i=0;i<5;i++){for(int j=0;j<=i;j++){输入数组元素p[i][j];}}for(int k=0;k<5;k++){for(int w=0;w<=k;w++){输出数组元素p[k][w];}}for(int a=4;a>0;a--){for(int s=0;s<=a;s++){if(p[a][s]大于p[a][s+1])p[a-1][s]等于p[a-1][s]加p[a][s];elsep[a-1][s] 等于p[a-1][s] 加p[a][s+1];}}输出p[0][0]}四.程序调试及运行结果分析五.实验总结虽然这个实验比较简单,但是通过这次实验使我更加了解的动态规划法的好处和、,在解决问题时要尝试使用动态规划,这样就有可能得到一种即简单复杂性有不高的算法。

附录:程序清单(程序过长,可附主要部分)#include<iostream.h>int main(){int m,n;int p[5][5];cout<<"输入矩阵的下三角的元素!!"<<endl;for(int i=0;i<5;i++){for(int j=0;j<=i;j++){cout<<"输入第"<<i+1<<"行"<<j+1<<"列的元素"<<endl;cin>>p[i][j];}}for(int k=0;k<5;k++){for(int w=0;w<=k;w++){cout<<p[k][w]<<" ";}cout<<endl;}for(int a=4;a>0;a--){for(int s=0;s<=a;s++){if(p[a][s]>p[a][s+1])p[a-1][s]=p[a-1][s]+p[a][s];elsep[a-1][s]=p[a-1][s]+p[a][s+1];}}cout<<"最大路径和为:"<<p[0][0]<<endl;return 0;}。

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

实验2 动态规划算法实现一、实验目标:1.熟悉动态规划算法实现的基本方法和步骤;2. 学会动态规划算法的实现方法和分析方法:二、实验内容:问题1:最长公共子序列的问题,测试数据X={ABCBDAB} Y={BDCABA}X={zhejiang university of technology} Y= {zhejiang university city college}1-1实验代码及截图#include<iostream>#include<cstring>using namespace std;//求得两个字符串的最大公共子序列长度int LCSLength(int m, int n,char* x, char* y,int **c, int **b){int i, j, len;//i=0 || j=0for (i = 0; i < m + 1; i++) c[i][0] = 0;for (j = 0; j < n + 1; j++) c[0][j] = 0;//i,j>0for (i = 1; i <= m; i++){for (j = 1; j <= n; j++){if (x[i] == y[j])//if (x[i - 1] == y[j - 1]){c[i][j] = c[i - 1][j - 1] + 1;b[i][j] = 1;}else if (c[i - 1][j] >= c[i][j - 1]){c[i][j] = c[i - 1][j];b[i][j] = 2;}else{c[i][j] = c[i][j - 1];b[i][j] = 3;}}}len = c[m][n];return len;}//构造最长公共子序列void LCS(int i, int j, char *x, int **b){if (i == 0 || j == 0) return;if (b[i][j] == 1){LCS(i - 1, j - 1, x, b);cout << x[i - 1];//c[i][]对应str1的第i-1个元素}else if (b[i][j] == 2){LCS(i - 1, j, x, b);}else{LCS(i, j - 1, x, b);}}int main(){char str1[1000], str2[1000];int i, m, n, len;cout << "请输入第一个字符串:";gets_s(str1);cout << "请输入第二个字符串:";gets_s(str2);m = strlen(str1);n = strlen(str2);int **c = new int*[m + 1]; //行for (i = 0; i < m + 1; i++)c[i] = new int[n + 1];//列int **b = new int*[m + 1];for (i = 0; i < m + 1; i++)b[i] = new int[n + 1];len = LCSLength(m, n, str1, str2, c, b);cout << "最长公共子序列的长度为:" << len << endl;cout << ("最长公共子序列为:");LCS(m, n, str1, b);cout << endl;system("pause");return 0;}实验截图:1-2实验总结:实验最开始考虑到穷举,但很明显时间复杂度过于庞大,利用最长公共子序列的最优子结构性质,结合书上代码进行实验,但实验中很明显没有考虑多种最长公共子序列的情况,这个可能要留待后续继续学习改进。

1-3参考书籍:本书部分代码。

2.最大子段和问题,比较三重循环,分治法和动态规划算法的效果,测试数据:1)(-2,11,-4,13,-5,-2)2)过去大约三百年间,太阳黑子数的时间数据如该链接所示,请问,历史上何时太阳黑子迎来了最大爆发?2.1-1.实验代码及截图#include<iostream>using namespace std;int MaxSum1(int n, int *a, int& besti, int& bestj){int sum = 0;for (int i = 1; i <= n; i++){for (int j = i; j <= n; j++){int thissum = 0;for (int k = i; k <= j; k++)thissum += a[k];if (thissum > sum){sum = thissum;besti = i;bestj = j;}}}return sum;}int MaxSum2(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 = MaxSum2(a, left, center);int rightsum = MaxSum2(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 MaxSum3(int n, int *a){int sum = 0, b = 0;for (int i = 1; i <= n; i++){if (b > 0) b += a[i];else b = a[i];if (b > sum)sum = b;}return sum;}int main(){int n,besti, bestj;int a[] = { -2, 11, -4, 13, -5, -2 };cout << "三重循环:"<<MaxSum1(6, a, besti, bestj) << endl;cout << "分治法:" << MaxSum2(a, 1, 6) << endl;cout << "动态规划:" << MaxSum3(6, a) << endl;system("pause");}实验截图:2.1-2实验总结:三重循环时间复杂度为n*n*n,分治法时间复杂度为nlogn,动态规划时间复杂度为n简单穷举是最容易想到的,但是论间接性或时间空间复杂度都是动态规划更加优越,通过实验感受动态规划的魅力2.1-3参考书籍:本书部分代码。

2.2-1实验代码及截图#include<iostream>#include<fstream>#include<vector>#include<sstream>#include<ctime>using namespace std;double MaxSum1(int n, double *a, int& besti, int& bestj) {double sum = 0;for (int i = 1; i <= n; i++){for (int j = i; j <= n; j++){double thissum = 0;for (int k = i; k <= j; k++)thissum += a[k];if (thissum > sum){sum = thissum;besti = i;bestj = j;}}}return sum;}double MaxSum2(double* a, int left, int right){double sum = 0;if (left == right)sum = a[left] > 0 ? a[left] : 0;else{int center = (left + right) / 2;double leftsum = MaxSum2(a, left, center);double rightsum = MaxSum2(a, center + 1, right);double s1 = 0;double lefts = 0;for (int i = center; i >= left; i--){lefts += a[i];if (lefts > s1)s1 = lefts;}double s2 = 0;double 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;}double MaxSum3(int n, double *a){double sum = 0, b = 0;for (int i = 1; i <= n; i++){if (b > 0) b += a[i];else b = a[i];if (b > sum)sum = b;}return sum;}{ifstream myfile("f:\\太阳黑子.txt");if (!myfile.is_open()) {cerr << "文件打不开" << endl;return 0;}vector<string> vec;string temp;while (getline(myfile, temp)){vec.push_back(temp);}double a[500];int i = 0;for (auto j = vec.begin(); j != vec.end(); j++) {istringstream is(*j);string s;int tmp = 0;while (is >> s)if (tmp == 2){double r = atof(s.c_str());a[i++] = r;}tmp++;}}i--;//int sum;int besti, bestj;clock_t cstart, cends;cstart = clock();double sum1 = MaxSum1(i, a, besti, bestj); cends = clock();int t1 = cends - cstart;cstart = clock();double sum2 = MaxSum2(a, 1, i);cends = clock();int t2 = cends - cstart;cstart = clock();double sum3 = MaxSum3(i,a);cends = clock();int t3 = cends - cstart;cout << "太阳黑子最大爆发年份:";cout << vec.at(bestj) << endl;//cout << vec.at(sum) << endl;cout << "三重循环用时:" << t1 <<"毫秒"<< endl;cout << "分治法用时:" << t2 << "毫秒" << endl;cout << "动态规划用时:" <<t3 << "毫秒" << endl;system("pause");}实验截图2.2-2实验总结:实验中最大字段和算法代码没有问题,反而是卡在了不定长度字符串输入和文件输入上,这里向其他同学求助才得到解决,反应vector不熟悉,之后要继续研究才行。

相关文档
最新文档