算法设计与分析实验报告c++实现(矩阵链相乘、投资问题、完全背包问题、数字三角形、最小生成树、背包问题)

一、实验目的

1.加深学生对分治法算法设计方法的基本思想、基本步骤、基本方法的理解与掌握;
2.提高学生利用课堂所学知识解决实际问题的能力;
3.提高学生综合应用所学知识解决实际问题的能力。

二、实验任务

用动态规划算法实现:

1、矩阵链相乘问题

image-20240403221859941

2、投资问题

image-20240403221853588

3、求解完全背包问题

问题描述:有n种重量和价值分别为wivi(1≤in)的物品,从这些物品中挑选总重量不超过W的物品,求出挑选物品价值总和最大的挑选方案,这里每种物品可以挑选任意多件。4、数字三角形
问题描述:在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或右下走。

4、数字三角形

问题描述:在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或右下走。

image-20240403221846682

用贪心算法实现:

5、最小生成树问题(Prim算法和Kruskal算法)

设G=(V,E)是一个无向连通网,生成树上各边的权值之和称为该生成树的代价,在G的所有生成树中,代价最小的生成树称为最小生成树(Minimal Spanning Trees)。

6、背包问题
【问题描述】设有编号为1、2、…、n的n个物品,它们的重量分别为w1、w2、…、wn,价值分别为v1、v2、…、vn,其中wi、vi(1≤i≤n)均为正数。
有一个背包可以携带的最大重量不超过W。求解目标:在不超过背包负重的前提下,使背包装入的总价值最大(即效益最大化),与0/1背包问题的区别是,这里的每个物品可以取一部分装入背包。

三、实验设备及编程开发工具

实验设备:惠普Win10电脑
开发工具:Java和python环境下,eclipse和pycharm编程工具

四、实验过程设计(算法思路及描述,代码设计)

一.矩阵相乘问题

基本原理和思路:
1、动态规划的第一步:寻找最优子结构。为方便起见,使用Ai…j表示AiAi+1…Aj的乘积结果矩阵。对于k(i<=k<j), 计算Ai…j所需要的计算量为:Ai…k 和 Ak+1…j 以及二者相乘的代价和。
2、设m[i][j]为Ai…j的最优计算顺序所要花费的代价。则其求解公式为:
if i == j, m[i][j] = 0; //因为只有一个矩阵时计算代码为0,即不需要计算。
m[i][j]=min{m[i][k] + m[k+1][j] + Pi-1PkPj} i<=k<j
3、为了能够输出求解顺序,需要保存区间中的一些分割点。假如Ai…j中的最优分割点为k,则我们使用s[i][j]=k。即在Ai…j中,分别计算Ai…k 和 Ak+1…j 所用的计算开销最小。
4、采用自底向上的表格法。依次求解矩阵长度为2,3,…,n的最优计算顺序。

代码实现如下:

#include <stdio.h>
int m[1002][1002],s[1002][1002];
void matrix_chain(int a[], int n)
{int l, i, j, k, tmp;for(l=2; l<=n; l++){for(i=1; i<=n-l+1; i++)		//长度为l的区间,其最小下标为1~n-l+1{j=i+l-1;m[i][j] = 0x7fffffff;for(k=i; k<j; k++)		//i~k, k+1~j, 所以k<j{tmp = m[i][k]+m[k+1][j]+a[i-1]*a[k]*a[j];if(tmp < m[i][j]){m[i][j] = tmp;s[i][j] = k;}}}}}
void print(int i, int j)
{if(i == j)printf("A%d",i);else{printf("(");print(i, s[i][j]);print(s[i][j]+1, j);printf(")");}
}
int main()
{int n, a[1002];int i,j,l;while(scanf("%d",&n)==1)	//输入有n个矩阵{for(i=0; i<n+1; i++)scanf("%d",&a[i]);//memset(m, 0x7fffffff,sizeof(m));for(i=0; i<n+1; i++)m[i][i] = 0;matrix_chain(a, n);printf("%d\n",m[1][n]);print(1, n);printf("\n");}return 0;
}

img

分析:时间复杂度为O(N3), 我们只需要存储一个矩阵就可以了,所以空间复杂度是 O(N2)。

二.投资问题

基本原理和思路:假设分配给第 i 个项目的钱数是 xi,问题描述为:
目标函数:max{f1(x1)+f2(x2)+…+fn(xn)}
约束条件:x1+x2+…+xn=m,xi∈N;设Fk(x)表示x元投给前k个项目的最大效益,k=1,2,…,n,x=1,2,…,m递推方程:Fk(x)=max{fk(xk)+Fk-1(x-xk)}(0≤xk≤x),k=2,3,…,n边界条件:F1(x)=f1(x),Fk(0)=0,k=1,2,…,n*说明:第k步,前后共分配x万元,分配给第k个项目xk;x-xk万元,分配给前k-1个项目;

代码实现如下:

#include <iostream>
#include <vector>using namespace std;int main() {int m, n;//m元钱,n项投资int i, j;int tmp_m, tmp_F = 0;cout << "请输入投资金额和项目数" << endl;cin >> m >> n;vector<vector<int>> f(n, vector<int>(m + 1));//f[i][x], 0<i<=n,0<=x<=m;vector<vector<int>> F(n, vector<int>(m + 1));//F[i][x],将x元钱投入到前i个项目上最大的收益//在第(i+1)个项目上投入0元,收益为0,注意i从0开始for (i = 0; i < n; i++) {f[i][0] = 0;}cout << "请输入各项目对应投资金额的收益(从1开始)" << endl;for (i = 0; i < n; i++) {for (j = 1; j < m + 1; j++) {cin >> f[i][j];}}//初始化,给F[0][0-m]赋值for (j = 0; j < m + 1; j++) {F[0][j] = f[0][j];//第一个项目上投入0-m元钱的最大收益等于f[0][0-m]}for (i = 1; i < n; i++) {//项目编号,从1开始for (j = 0; j < m + 1; j++) {//钱数,从0开始for (tmp_m = 0; tmp_m <= j; tmp_m++) {//递推公式tmp_F = F[i - 1][j - tmp_m] + f[i][tmp_m];//取最大值if (tmp_F > F[i][j]) {F[i][j] = tmp_F;}	}}}cout << "最大总收益: " << F[n - 1][m] << endl;
}

分析:复杂度 W(n,m)=O(nm2)。

三. 求解完全背包问题

基本原理和思路:1.设置动态规划二维数组dp,dp[i][j]表示从前i个物品中选出重量不超过j(或者剩余容量为j)的物品的最大总价值。
①显然有边界条件:dp[i][0]=0(背包不能装入任何物品时,总价值为0),dp[0][j]=0(没有任何物品可装入时,总价值为0),可以采用memset函数一次性初始化为0.
②另外设置二维数组fk,其中fk[i][j]存放dp[i][j]得到最大值时物品i挑选的件数。

代码实现如下:

//求解完全背包问题的算法
#include <stdio.h>
#include <string.h>
#define MAXN 20				//最多物品数
#define MAXW 100			//最大限制重量
#define max(x,y) ((x)>(y)?(x):(y))
//问题表示
int n,W;
int w[MAXN],v[MAXN];
//求解结果表示
int dp[MAXN+1][MAXW+1],fk[MAXN+1][MAXW+1];
int solve()					//求解多重背包问题
{int i,j,k;for (i=1;i<=n;i++){for (j=0;j<=W;j++)for (k=0;k*w[i]<=j;k++){if (dp[i][j]<dp[i-1][j-k*w[i]]+k*v[i]){dp[i][j]=dp[i-1][j-k*w[i]]+k*v[i];fk[i][j]=k;		//物品i取k件}									}}return dp[n][W];
}
void Traceback()				//回推求最优解
{int i=n,j=W;while (i>=1){printf("物品%d共%d件 ",i,fk[i][j]);j-=fk[i][j]*w[i];		//剩余重量i--;}printf("\n");
}
void prin(){   //查看dp数组与fk数组 int i,j,k;printf("fk[i][j]:\n");for (i=1;i<=n;i++){for (j=0;j<=W;j++){printf("%d ",fk[i][j]);}printf("\n");}printf("dp[i][j]:\n");for (i=1;i<=n;i++){for (j=0;j<=W;j++){printf("%d ",dp[i][j]);}printf("\n");}
}
int main()
{w[1]=3; w[2]=2; w[3]=6;w[4]=2;v[1]=7; v[2]=2; v[3]=5;v[4]=3;n=4; W=9;memset(dp,0,sizeof(dp));memset(fk,0,sizeof(fk));printf("最优解:\n");printf("  总价值=%d\n",solve());printf("  方案: ");Traceback();printf("\n");prin();return 0;
} 

img

分析:空间复杂度O(nV) 时间复杂度O(nV)。

四.数字三角形

基本原理和思路:MaxSum(i,j):从第i行j列到底边的最大数字之和
从最后一行开始递推,MaxSum(n,j)=D(n,j)//n行j列,MaxSum(n-1,j) = D(n-1,j) + max( MaxSum(n,j) , MaxSum(n,j+1) )
然后为了减少空间,不需要用二维数组来存储MaxSum(n,j)的值,只需要求MaxSum(n,j)的时候存储下一行MaxSum(n+1,j)的值就可以,然后计算完第n行的MaxSum之后再覆盖原来的第n+1行的MaxSum的值。

代码实现如下:

#include <iostream>
#include <algorithm>
using namespace std;
#define Max 101
int D[Max][Max];
int n;
int maxSum[Max][Max];
int MaxSum(int i,int j)
{if(maxSum[i][j]!=-1)return maxSum[i][j];if(i==n)maxSum[i][j]=D[i][j];else{int x=MaxSum(i+1,j);int y=MaxSum(i+1,j+1);maxSum[i][j]=max(x,y)+D[i][j];}return maxSum[i][j];
}
int main()
{int i,j;cin>>n;for(i=1;i<=n;i++)for(j=1;j<=i;j++){cin>>D[i][j];maxSum[i][j]=-1;}cout<<MaxSum(1,1)<<endl;return 0;
}

分析:时间复杂度是n2。

五.最小生成树问题

prim算法

基本原理和思路:设G=(V, E)是具有n个顶点的连通网,
T=(U, TE)是G的最小生成树,
T的初始状态为U={u0}(u0∈V),TE={ },
重复执行下述操作:
在所有u∈U,v∈V-U的边中找一条代价最小的边(u, v)并入集合TE,同时v并入U,直至U=V。
数组lowcost[n]:用来保存集合V-U中各顶点与集合U中顶点最短边的权值,lowcost[v]=0表示顶点v已加入最小生成树中;
数组adjvex[n]:用来保存该边所依附的(集合V-U中各顶点与集合U中顶点的最短边)集合U中的顶点。

代码实现如下:

void prime(MGraph G){for(int i=1;i<G.vertexNu;i++){lowcost[i]=G.arc[0][i];  adjvex[i]=0;}lowcost[0]=0;for(i=1;i<G.vertexNum;i+++){k=MinEdge(lowcost,G.vertexNum)cout<<K<<adjvex[k]<<lowcost[k];lowcost[k]=0;for(j=1;j<G.vertexNum;j++)if((G.arc[k][j]<lowcost[j]){lowcost[j]=G.arc[k][j];arcvex[j]=k;}
}

六.背包问题

基本原理和思路:利用动态规划思想 ,子问题为:f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。其状态转移方程是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} //这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只和前i-1件物品相关的问题。
1.如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1; v];
2.如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为
v-Ci的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值Wi

代码实现如下:

int n = 5;
double W = 100;
struct NodeType
{double w;double v;double p;bool operator<(const NodeType &s)const{return p > s.p;}
};NodeType A[] = { {0},{10,20},{20,30},{30,66},{40,40},{50,60} };
double V;
double x[MAXN];void Knap()
{V = 0;double weight = W;memset(x, 0, sizeof(x));int i = 1;while (A[i].w < weight)//物品可以全部装入{x[i] = 1;weight -= A[i].w;V += A[i].v;i++;}if (weight > 0)//余下物品重量大于0{x[i] = weight / A[i].w;V += x[i] * A[i].v;}
}

分析:时间复杂度为O(nlog2n)

实验小结(包括问题和解决方法、心得体会等)

经过这次试验收获颇多,代码实现过程中也遇到一些问题,有的问题确实也有一定的难度,所以也是通过了网络搜索才得出的解决方案,思维上得到了很好的训练,同时也明白了一个道理:纸上得来终觉浅,绝知此事要躬行。尤其是算法和编程这门课程更是要勤于动手方能获得收获。希望下次实验或者之后的编程学习能吸取这些教训。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/624148.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【微信小程序之分包】

微信小程序之分包 什么是分包分包的好处分包前的结构图分包后的结构图分包的加载规则分包的体积限制使用分包打包原则引用原则独立分包独立分包的配置方法独立分包的引用原则分包预下载配置分包的预下载分包预下载限制 什么是分包 分包指的是把一个完整小程序项目&#xff0c;…

突破编程_前端_SVG(使用 svg-pan-zoom 库进行平移与缩放)

1 svg-pan-zoom 概述 svg-pan-zoom 是一个轻量级、高性能且易于使用的 JavaScript 库&#xff0c;专为增强 SVG 图像的浏览体验而设计。它提供了平移和缩放功能&#xff0c;使用户能够无缝探索大型或复杂的 SVG 图形。这个库允许用户对SVG图像进行交互操作&#xff0c;包括缩放…

新版AndroidStudio使用switch-case语句时出现Constant expression required错误

原因: 在新版的Android Studio中使用JDK17以上版本&#xff0c;会出现switch语句报错"Constant expression required"的问题&#xff0c;这是因为在JDK17中switch语句的条件表达式支持使用枚举类型&#xff0c;而这个特性还没有被支持。 解决方法: ①在gradle.prope…

Github 2024-04-12 开源项目日报 Top10

根据Github Trendings的统计,今日(2024-04-12统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目6TypeScript项目2Cuda项目1C++项目1C项目1HTML项目1Jupyter Notebook项目1JavaScript项目1Python - 100天从新手到大师 创建周期:22…

HTTP/1.1特性总结

优点 【简单&#xff0c;灵活和易于扩展&#xff0c;应用广泛和跨平台】 1.简单&#xff1a; http基本的报文格式就是headerbody&#xff0c;头部信息也是key-value简单的文本形式&#xff0c;易于理解&#xff0c;降低了学习和使用的门槛 2.灵活和易于扩展&#xff1a; &…

python-常用数据结构(2)

6、某企业为职工发放奖金:如果入职超过5年,且销售业绩超过15000元的员工,奖金比例为0.2;销售业绩超过10000元的员工,奖金比例为0.15:销售业绩超过5000元的员工,奖金比例为0.1;其他奖金比例为0.05。如果是人职不超过5年,且销售业绩超过4000的员工,奖金比例为0.045;否则为0.01。输…

前端ocr技术:electron+vue3中使用tesseract插件识别图片中字符

同学们可以私信我加入学习群&#xff01; 正文开始 前言一、electron各种csp问题二、试用插件总结 前言 项目需要ocr技术识别图片中的中文字符&#xff0c;本来这部分是后端的工作&#xff0c;但是因为各种原因&#xff0c;决定前端也做一个版本。 在ai时代之前&#xff0c;o…

bugku-cryton 把猪困在猪圈里

打开题目得到一串字符&#xff0c;发现最后有等号&#xff0c;尝试buase64解码&#xff0c;发现文字解码不行&#xff0c;试试图片解码 解码得到一串图片密文&#xff0c;根据经验是猪圈密码&#xff0c;查找相关表格对应 一一对应得到flag{thisispigpassword} 参考猪圈密文链…

PyCharm 2024.1 发布:全面升级,助力高效编程!

PyCharm 2024.1 发布&#xff1a;全面升级&#xff0c;助力高效编程&#xff01; 文章目录 PyCharm 2024.1 发布&#xff1a;全面升级&#xff0c;助力高效编程&#xff01;摘要引言 Hugging Face&#xff1a;模型和数据集的快速文档预览针对 JavaScript 和 TypeScript 的全行代…

【C++对于C语言的扩充】函数重载、引用以及内联函数

文章目录 &#x1f680;前言&#x1f680;函数重载注意&#xff1a;✈️为什么C可以实现函数重载&#xff0c;而C语言却不行呢&#xff1f; &#x1f680;引用✈️引用的特性✈️C中为什么要引入引用✈️引用与指针的区别 &#x1f680;内联函数✈️内联函数特性 &#x1f680;…

腾讯云最新优惠活动及领券入口整理分享

腾讯云近期的优惠活动丰富多样&#xff0c;旨在为用户提供更优惠的产品和服务。以下是一些腾讯云最新的优惠活动及领券入口的整理分享。 优惠活动&#xff1a; 腾讯云最新活动&#xff1a;https://txy.ink/act/ 1、腾讯云新客专属福利&#xff1a;新客户可以无门槛领取代金券&a…

windows下已经创建好了虚拟环境,但是切换不了的解决方法

用得多Ubuntu&#xff0c;今天用Windows重新更新anaconda出问题&#xff0c;重新安装之后&#xff0c;打开pycharm发现打开终端之后&#xff0c;刚开始是ps的状态&#xff0c;后面试了网上改cmd的方法&#xff0c;终端变成c盘开头了 切换到虚拟环境如下&#xff1a;目前的shell…