算法设计与分析实验报告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.mfbz.cn/a/549527.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

懒人建站工具过时了?试试这6个WordPress主题,1小时实现高效建站

懒人建站工具&#xff0c;凭借简单易用、快速上手和个性化定制的特点&#xff0c;为不熟悉代码和程序的人提供了搭建美观实用网站的便捷途径。无需专业的前端开发知识&#xff0c;无需雇佣专业开发人员&#xff0c;用户便能轻松实现网站搭建&#xff0c;满足个人或企业需求。懒…

novel-plus文件部分

环境配置。windows下需要将application-dev.yml添加盘符&#xff0c;固定路径 在FileController中&#xff0c;存在任意文件上传&#xff0c;也就是在 存在问题&#xff0c;确实是任意文件上传&#xff0c;任意文件都可以上传&#xff0c;但是上传jsp等文件时&#xff0c;会…

windows编译xlnt,获取Excel表里的数据

用git拉取项目 这个文件是空的 要用git拉下来&#xff0c;使用终端编译xlnt库 点击解决方案 运行生成 然后新建项目&#xff0c;配置好库&#xff0c; #include <iostream> #include <xlnt/xlnt.hpp>int main() {// 打开 Excel 文件xlnt::workbook workbook;workb…

微信小程序scroll-view组件

一、介绍 当一个容器内容很多时&#xff0c;若容器无法显示完整内容&#xff0c;则可通过滚动操作查看所有内容 在微信小程序中scroll-view组件可以实现滚动效果 二、scroll-view组件的属性值 &#xff08;1&#xff09;scroll-x 【boolean型】 允许横向滚动条&#xff0c;默…

【C++】开始使用stack 与 queue

送给大家一句话&#xff1a; 忍受现实给予我们的苦难和幸福&#xff0c;无聊和平庸。 – 余华 《活着》 开始使用queue 与 stack 1 前言2 stack与queue2.1 stack 栈2.2 queue 队列2.3 使用手册 3 开始使用Leetcode 155.最小栈牛客 JZ31 栈的弹出压入序列Leetcode 150.逆波兰表达…

共享桌面,3分钟自己实现一个吧,还能听见麦克风声音哦

前言 关于【SSD系列】&#xff1a; 前端一些有意思的内容&#xff0c;旨在3-10分钟里&#xff0c; 500-1000字&#xff0c;有所获&#xff0c;又不为所累。 共享桌面程序&#xff0c;哇&#xff0c;高大尚耶&#xff01;其实不然&#xff0c;让我带你3分钟实现桌面共享程序&am…

【Entity Framework】你知道如何处理无键实体吗

【Entity Framework】你知道如何处理无键实体吗 文章目录 【Entity Framework】你知道如何处理无键实体吗一、概述二、定义无键实体类型数据注释 三、无键实体类型特征四、无键实体使用场景五、无键实体使用场景六、无键使用示例6.1 定义一个简单的Blog和Post模型&#xff1a;6…

sqlilabs靶场1—20题学习笔记(思路+解析+方法)

前几个题目较为简单&#xff0c;均尝试使用各种方法进行SQL注入 第一题 联合查询 1&#xff09;思路&#xff1a; 有回显值 1.判断有无注入点 2.猜解列名数量 3.判断回显点 4.利用注入点进行信息收集 爆用户权限&#xff0c;爆库&#xff0c;爆版本号 爆表&#xff0c;爆列&…

AI 领域精选高质量信息源分享

我在这篇 ChatGPT 发布一周年的总结文章中大模型时代&#xff0c;程序员如何实现自我成长&#xff1f;——一名普通开发者的 ChatGPT 一周年记&#xff0c;已经推荐了不少优质的信息源&#xff0c;但主要还是偏技术向&#xff0c;随着我自己的身份从纯研发角色转变为产品&#…

【Linux】服务器硬件及RAID配置实战

目录 一、服务器 1.服务器 2.查看服务器信息 二、RAID 磁盘阵列 三、软RAID的创建和使用 1.添加硬盘&#xff0c;fdisk分区&#xff0c;分区类型ID设置为 fd 2.使用mdadm创建软raid 3.格式化 4.挂载使用 5.mdadm 一、服务器 1.服务器 分类机架式居多 塔…

Qt | 事件第二节

Qt | 事件第一节书接上回 四、事件的接受和忽略 1、事件可以被接受或忽略,被接受的事件不会再传递给其他对象,被忽略的事件会被传递给其他对象处理,或者该事件被丢弃(即没有对象处理该事件) 2、使用 QEvent::accept()函数表示接受一个事件,使用 QEvent::ignore()函数表示…

牛客网刷题 | BC51 及格分数

描述 KiKi想知道他的考试分数是否通过&#xff0c;请帮他判断。从键盘任意输入一个整数表示的分数&#xff0c;编程判断该分数是否在及格范围内&#xff0c;如果及格&#xff0c;即&#xff1a;分数大于等于60分&#xff0c;是输出“Pass”&#xff0c;否则&#xff0c;输出“…

【Entity Framework】你必须要了解EF中数据查询之数据加载

【Entity Framework】你必须要了解EF中数据查询之数据加载 文章目录 【Entity Framework】你必须要了解EF中数据查询之数据加载一、概述二、预先加载2.1 包含多个层级2.2 经过筛选的包含 三、显示加载3.1查询关联实体 四、延时加载4.1 不使用代理进行延迟加载 一、概述 Entity…

数据分析(2)

数据分析&#xff08;2&#xff09; 本文介绍pandas的另一种数据类型DataFrame,中文叫数据框 DataFrame 定义&#xff1a; DataFrame是一个二维的矩阵数据表&#xff0c;通过行和列&#xff0c;可以定位一个值。 在某种程度上&#xff0c;可以认为DataFrame是“具有相同ind…

自定义类型: 结构体 (详解)

本文索引 一. 结构体类型的声明1. 结构体的声明和初始化2. 结构体的特殊声明3. 结构体的自引用 二. 结构体内存对齐1. 对齐规则2. 为啥存在对齐?3. 修改默认对齐值 三. 结构体传参四. 结构体实现位段1. 什么是位段?2. 位段的内存分配3. 位段的应用4. 位段的注意事项 ​ 前言:…

Python leetcode 2906 构造乘积矩阵,力扣练习,矩阵递推,经典递推题目,递推代码实战

leetcode 2906 构造乘积矩阵&#xff0c;矩阵递推 1.题目描述 给你一个下标从 0 开始、大小为 n * m 的二维整数矩阵 grid &#xff0c;定义一个下标从 0 开始、大小为 n * m 的的二维矩阵 p。如果满足以下条件&#xff0c;则称 p 为 grid 的 乘积矩阵 &#xff1a; 对于每个元…

JavaWeb前端/后端开发规范——接口文档概述及YApi平台的使用

前言&#xff1a; 整理下笔记&#xff0c;打好基础&#xff0c;daydayup!!! 接口文档 什么是接口文档&#xff1f; 目前主流的开发模式为前后端分离式开发&#xff0c;为了方便前后端的对接&#xff0c;就需要使用接口文件进行统一规范。 接口文档记载什么信息&#xff1f; 1&…

Mac搭建Java环境【环境搭建】

Mac搭建Java环境【环境搭建】 1 安装Java SDK 官网地址&#xff1a;https://www.oracle.com/java/technologies/downloads/archive/ 下载dmg&#xff0c;双击之后无脑安装即可。 # 进入 JDK 安装目录 cd /Library/Java/JavaVirtualMachines# 查看文件 ls# 输入 cd ~# 打开环…

短剧分销系统:引领影视娱乐新潮流,开启内容变现全新模式!

近年来&#xff0c;随着互联网的飞速发展和人们生活节奏的加快&#xff0c;短剧项目在我国逐渐崭露头角&#xff0c;并在短时间内吸引了大量观众和投资者的目光。短剧以其时长短、剧情紧凑、制作精良等特点&#xff0c;迅速在视频市场中占据了一席之地。 一、短剧项目发展现状…

vue学习日记22:非父子通信(拓展)-provideinject

一、概念 二、实践 代码 App <template><div class"app">我是APP组件<button click"change">修改数据</button><SonA></SonA><SonB></SonB></div> </template><script> import SonA …
最新文章