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

一、实验目的

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

二、实验任务

1、矩阵链相乘问题

image-20240404002318769
2、投资问题

image-20240404002332398

3、背包问题

img

4、TSP问题
旅行家要旅行n个城市,要求经历各个城市且仅经历一次,然后回到出发城市,并要求所走的路程最短。
5、数字三角形
问题描述:在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或右下走。

image-20240404002353934

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

编程开发工具:Microsoft Visual c++

四、实验过程设计(算法设计过程)

(一)、矩阵链相乘问题

1 动态规划的4个步骤为:
(1).寻找一个最优子结构。
对于原问题,我们使用表示乘积的结果矩阵,如果我们将在处进行一次括号划分,假设将其划分为和两部分,则=++(两个划分矩阵合并的代价)。假设这样划分是最优的,则只需继续在和上继续取到最佳划分即可。
(2). 递归地定义最优解的值
在原问题中,我们定义数组m[i][j]表示计算矩阵所需乘法的最小值,则原问题计算所需最小代价为m[1][n]。
如果k表示矩阵i到j之间的划分点,那么m数组的公式为:

20150506001233277 (3).计算最优代价
如果直接递归计算的话,我们会发现计算量仍然会很大,并没有明显改善。因此在这里,我们使用自底向上的方法进行计算,并且在计算中保存已经计算过的值,这样当上一层划分计算时,直接调用下层之前计算保存过的值即可。
在这整个过程中,我们使用m[i][j]从矩阵i到j的最小代价,用s[i][j]保存最小代价时的划分位置。根据2步骤的公式,我们只需按链条长度递增的顺序进行求解即可。在这里,它的长度是从2到n的(长度为1时直接为0)。由于只知道链的长度,因此有多个乘法问题,因此我们需要求解出所有乘法问题的最小代价。
(4).构造最优解
2 源程序

#include<stdio.h>
#include<string.h>
#define N 1000
int m[N][N];//m[i][j]表示从第i个矩阵乘到第j个矩阵所需的最小代价
int s[N][N];  //s[i][j]表示最优值m[i][j]对应的分割点
int p[N];     //p[]代表矩阵链

void MATRIX_CHAIN_ORDER(int p[], int n) //对矩阵链p求解最佳组合方法
{
    for(int i = 1; i <= n; i++) //子问题链长1时代价为0
        m[i][i] = 0;
    //对子问题链长2到n从小到大求出代价
    for(int length = 2; length <= n; length++) //枚举子问题链长
    {
        //在对应链长下求出所有情况
        for(int i = 1; i <= n-length+1; i++)  //所有情况的开始位置
        {
            int j = i+length-1;
            m[i][j] = 999999;   //此时求出从i到j的最小代价m[i][j]=min{m[i][k]+m[k+1][j]+Pi-1*Pk*Pj}
            for(int k = i; k <= j-1; k++)
            {
                if(m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j] < m[i][j])
                {
                    m[i][j] = m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
                    s[i][j] = k;
                }
            }
        }
    }
}

void PRINT_OPTIMAL_PARENS(int s[][N], int start, int ends)//利用表s输出从start乘到ends的最优方案
{
    if(start == ends)
        printf("A[%d]", start);
    else
    {
        printf("(");
        PRINT_OPTIMAL_PARENS(s, start, s[start][ends]);
        PRINT_OPTIMAL_PARENS(s, s[start][ends]+1, ends);
        printf(")");
    }
}

int main()
{
    int number;
    printf("请输入待乘矩阵的个数:\n");
    while(scanf("%d",&number) && number>0)
    {
        memset(m, 0, sizeof(m));
        memset(p, 0, sizeof(p));
        printf("请输入矩阵链:\n");
        for(int i = 0; i <= number; i++)
            scanf("%d", &p[i]);
        MATRIX_CHAIN_ORDER(p, number);
        PRINT_OPTIMAL_PARENS(s, 1, number);
        printf("\n");
        printf("请输入待乘矩阵的个数:\n");
    }
    return 0;
}

(二)、投资问题

1 算法分析
根据题目要求的项目个数,将解题思路分为项目数个阶段:
第一阶段:只考虑第一个项目,即将所有的资金都投资给该项目,那么此时可以获取的利益可以计算出来;
第二阶段:将第二个项目加进去,即投资的资金可以同时分配给两个项目,那么此时可以获取的利益可以计算出来;
第三阶段:将第三个项目加进去,即投资的资金可以同时分配给三个项目,同样可以用上述方法得到此时能获取的利益。
后面以此类推。
2 源程序

 #include<stdio.h> 
#include<conio.h>
 void main() 
{      
void jie(int,int,int d[][6]);     
void Invest(int m,int n,int f[][6],int g[][6],int d[][6]);    
int m=5,n=4,f[5][6],d[5][6];   
int g[5][6]={{0},{0,11,12,13,14,15},
{0,0,5,10,15,20},{0,2,10,30,32,40},{0,20,21,22,23,24}};     
Invest(m,n,f,g,d);     
printf("可获得的最大收益为:%d\n",f[4][5]);     
jie(m,n,d); 
 
} 
 void Invest(int m,int n,int f[][6],int g[][6],int d[][6]) 
{   
int i,j,k,s;  
for(j=0;j<=m;j++)       
{    
f[1][j]=g[1][j];d[1][j]=j;}
           for(i=2;i<=n;i++)               
 for(j=0;j<=m;j++)                  
{    f[i][j]=0;                      
for(k=0;k<=j;k++)                      
 { 
s=f[i-1][j-k]+g[i][k];                           if(s>f[i][j])     
{   
f[i][j]=s;  d[i][j]=k;  
}                     
  }               
 }    
}  

void jie(int m,int n,int d[][6])
{  
int s=m;  int k[5];  
int i;  
k[n]=d[n][m];  
for(i=n-1;i>0;i--)  
{        
 s = s-k[i+1];        
k[i] = d[i][s];  
}  

for(i=1;i<=4;i++)   
printf("%5d",k[i]);  
printf("\n");    
 getch();
 }         

(三)、背包问题

1 算法过程

image-20240404002628533

image-20240404002652707

image-20240404002709939

#include <iostream>  
#include <cstring>  
using namespace std;

const int N = 150;
char t[N] = {'A','B','C','D'};
int v[N] = { 0, 12, 8, 9, 5 };
int w[N] = { 0, 15, 10, 12, 8 };
int x[N];
int m[N][N];
int c = 30;
int n = 4;
void traceback()
{
	for (int i = n; i>1; i--)
	{
		if (m[i][c] == m[i - 1][c])
			x[i] = 0;
		else
		{
			x[i] = 1;
			c -= w[i];
		}
	}
	x[1] = (m[1][c]>0) ? 1 : 0;
}

int main()
{
	memset(m, 0, sizeof(m));
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= c; j++)
		{
			if (j >= w[i])
			if (m[i - 1][j]> m[i - 1][j - w[i]] + v[i])
				m[i][j] = m[i - 1][j];
			else 
				m[i][j] = m[i - 1][j - w[i]] + v[i];
			else
				m[i][j] = m[i - 1][j];
		}
	}/*
	 for(int i=1;i<=6;i++)
	 {
	 for(int j=1;j<=c;j++)
	 {
	 cout<<m[i][j]<<' ';
	 }
	 cout<<endl;
	 }
	 */
		printf("项目  ");
		for (int q = 0; q < 4; q++)
		{
			printf("   %c",t[q]);
		}
		
		printf("\n");
		printf("投资额");

		for (int q = 1; q < 5; q++)
		{
			printf("%4d", v[q]);
		}
		
		printf("\n");
		printf("收益  ");
	
		for (int q = 1; q < 5; q++)
		{
			printf("%4d", w[q]);
		}
		printf("\n");
	traceback();
	cout << "项目选择结果是:" ;
	for (int i = 1; i <= n; i++)
		cout <<"   "<< x[i];
		cout << endl;
	system("pause");
	return 0;
}

(四)TSP问题

1 动态规划解决方法
假定我们从城市1出发,经过了一些地方,并到达了城市j。毋庸置疑,我们需要记录的信息有当前的城市j。同时我们还需要记录已经走过的城市的集合。同理,使用S记录未走过的城市的集合也可以的,且运算方便。
于是我们可以得出状态转移方程 go(S,init)=min{go(S−i,i)+dp[i][init]}∀s∈Sgo(S,init)=min{go(S−i,i)+dp[i][init]}∀s∈S go(s,init)表示从init点开始,要经过s集合中的所有点的距离
因为是NP问题,所以时间复杂度通常比较大。使用dis[s][init]用来去重,初始化为-1,如果已经计算过init—>S(递归形式),则直接返回即可.
2 源程序

#include<iostream>
#include<cmath> 
#include<iomanip>
using namespace std;
int s;
int N;//点的个数 
int init_point;
double x[20];
double y[20];
double dp[20][20];//两个城市的距离 
double dis[1048577][20];//2^20=1048576 表示出发点到S集合是否已经访问过 
double go(int s,int init)
{
    if(dis[s][init]!=-1) return dis[s][init];//去重 
    if(s==(1<<(N-1))) return dp[N-1][init];//只有最后一个点返回 
    double minlen=100000;
    for(int i=0;i<N-1;i++)//只能在1到n-2点中查找 
    {
        if(s&(1<<i))//如果i点在s中且不为发出点 
        {
            if(go(s&(~(1<<i)),i)+dp[i][init]<minlen)
                minlen=go(s&(~(1<<i)),i)+dp[i][init];
        } 
    } 
    return dis[s][init]=minlen;
}
int main()
{
    int T;
    cin>>T;
    while(T--)//测试样例数 
    {
        cin>>N;
        for(int i=0;i<N;i++)
            cin>>x[i]>>y[i];//读入城市的坐标 
        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++)
            {
                dp[i][j]=sqrt(pow((x[i]-x[j]),2)+pow((y[i]-y[j]),2));
                //计算两个城市的距离 
            }   

        for(int i=0;i<pow(2,N);i++)
            for(int j=0;j<N;j++)
                dis[i][j]=-1;//去重数组初始化  
        init_point=0;
        s=0; 
        for(int i=1;i<N;i++)
            s=s|(1<<i);//从1开始,保证初始点没有在S里面           
        double distance=go(s,init_point);
        cout<<fixed<<setprecision(2)<<distance<<endl;

    }       
} 

(五)数字三角形

1 动态规划解决问题
设 d( i , j )表示数字三角形中的第 i 行第 j 个点。 max[i][j]表示 第 i 行 第 j 个数字到低端的最佳路径之和,则原问题的解就是 max[1][1] 的值了。
  从d( i,j )这个点向下走,显然只能走 d( i+1,j ) 和 d( i+1 ,j+1 ) 这两个点了。
  而 max[i][j] 的最优值= d( i,j) 的值 + max{ max[i+1][j] ,max[i+1][j+1] }。
  所以,我们可以至底向上来计算。先计算最后一层的点的,然后倒二层的,一直算到第一层。
2 源程序

#include <stdlib.h>
int main()
{
	int n, a[101][101], d[101][101], i, j, k;
	scanf_s("%d", &n);
	for (i = 1; i <= n; i++)
	for (j = 1; j <= i; j++)
		scanf_s("%d", &d[i][j]);
	for (j = 1; j <= n; j++)
		a[n][j] = d[n][j];//从最后一行开始;
	for (i = n - 1; i >= 1; i--)
	for (j = 1; j <= i; j++)
	{
		if (a[i + 1][j + 1]>a[i + 1][j]) a[i][j] = d[i][j] + a[i + 1][j + 1];
		else
			a[i][j] = d[i][j] + a[i + 1][j];
	}
	printf("%d\n", a[1][1]);
	system("pause");
	return 0;
}

五、实验结果及算法复杂度分析

(一) 矩阵链相乘问题
1 实验结果

image-20240404002917707

2 算法复杂度分析
计算时间复杂度为:
O ( 1 + 1 + 2 + … + 1 + 2 + … + ( N − 1 ) ) = O ( ∑ n = 1 N − 1 ∑ r = 1 n r ) = O ( ∑ n = 1 N − 1 ( n + 1 ) n 2 ) = O ( ∑ n = 1 N − 1 n 2 + ∑ n = 1 N − 1 n ) = O ( N 3 ) O({1}+{1+2}+…+{1+2+…+(N−1)})\\ =O(∑n=1N−1∑r=1nr)\\ =O(∑n=1N−1(n+1)n2)\\ =O(∑n=1N−1n2+∑n=1N−1n)\\ =O(N3) O(1+1+2++1+2++(N1))=O(n=1N1r=1nr)=O(n=1N1(n+1)n2)=O(n=1N1n2+n=1N1n)=O(N3)

(二)投资最少问题
1 实验结果

image-20240404002951664

2 算法复杂度分析
时间复杂度为O(nC),把一个多维决策问题转化为多个一维最优化问题,能求出全局极大或者极小,但是缺点在于空间占据过多。

(三)背包问题
1 实验结果

image-20240404003004793

2 算法复杂度分析
时间复杂度为O(n),每次循环都需要进行比较,

(四)TSP问题
1 实验结果

image-20240404003016497

2 算法复杂度

img

(五) 数字三角形
1 实验结果

image-20240404003031183

2 算法复杂度
动态规划将计算过的数值保存,再次要用的时候直接取就可以大大减少计算次数,得出时间复杂度就是 O ( n ) = n 2 O(n)=n^2 On=n2

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

通过实现动态规划的这些题目,对动态规划算法有了进一步的了解,先分析问题,判断是否具有最优子结果和重叠字问题的性质。动态规划算法是由单阶段的决策最优逐步转化为多阶段的决策最优,最后构造一个最优解。经过反复的调试操作,程序运行才得出结果。

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

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

相关文章

自动化测试提速必备 - 并发编程

在自动化测试领域&#xff0c;多线程和多进程技术被广泛应用于提高测试的执行效率和性能。通过并发运行测试用例&#xff0c;可以显著缩短测试周期&#xff0c;特别是在面对大量测试用例或者需要在多个环境中进行测试时尤为重要。 在实际的自动化测试中&#xff0c;我们经常碰…

2024年【T电梯修理】考试总结及T电梯修理考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 T电梯修理考试总结考前必练&#xff01;安全生产模拟考试一点通每个月更新T电梯修理考试技巧题目及答案&#xff01;多做几遍&#xff0c;其实通过T电梯修理试题及解析很简单。 1、【多选题】修理工陶、陈&#xff0c…

废石颗粒运动理论模型及Python模拟

学者赵国彦等[26]对于废石颗粒运动的理论模型进行做了较为充分的研究&#xff0c;本文在以往研究的基础上对相关推导进行补充修正&#xff0c;并以某金矿充填废石的基本物理性能测试数据为基础&#xff0c;对废石运动理论模型的进行模拟。 4.2.1废石运动理论模型 4.2.1.1废石…

AI大模型探索之路-应用篇10:Langchain框架-架构核心洞察

目录 前言 一、LangChain设计目标 二、LangChain设计之道 三、LangChain典型应用 1、简单的问答Q&A over SQL CSV: 2、聊天机器人Chatbots: 3、总结摘要Summarization: 4、网页爬虫Web scraping: 5、本地知识库&#xff08;Q&A with RAG): 三、LangChain架构…

数字阅览室-数字图书馆体系的重要补充

数字阅览室&#xff08;Digital Reading Room&#xff09;是一种依托现代信息技术&#xff0c;特别是互联网、数字媒体技术和数据库管理技术&#xff0c;为用户提供在线访问、阅读、学习和研究各类数字化文献资源的虚拟空间。它是数字图书馆服务体系中的一个重要组成部分&#…

文库配置异步转换(宝塔)| 魔众文库系统

执行以下操作前提前进入网站根目录&#xff0c;如 cd /www/wwwroot/example.com执行 artisan 命令前请参照 开发教程 → 开发使用常见问题 → 如何运行 /www/server/php/xxx/bin/php artisan xxx 命令 步骤1&#xff0c;生成数据库队列表迁移文件 在执行该步骤前&#xff0c;请…

数据可视化高级技术Echarts(折线图)

目录 一、什么是折线图 二、如何实现 1.基本折线图 2.如何变得平滑只需要定义&#xff1a; smooth 3.如何定义线条的样式 color&#xff1a;设置线的颜色 width&#xff1a;设置线宽 type&#xff1a;设置线的类型 4.如何定义节点样式 symbol symbolSize&#xff1a…

开发着开发着,盘满了

办公电脑突然报家目录不足1G空间了, 使用 Disk Usage Analyzer 工具打开看了下, 微软还真没把我当穷人, 一个vs code给我占了30几个G的空间. 大家可能也遇到这种情况的, 看到真的让人窒息, 以前windows上被VS studio 支配C盘的感觉又回来了. 不过这个ubuntu好处理点, 我该删…

算法打卡day32

今日任务&#xff1a; 1&#xff09;738.单调递增的数字 2&#xff09;968.监控二叉树 738.单调递增的数字 题目链接&#xff1a;738. 单调递增的数字 - 力扣&#xff08;LeetCode&#xff09; 文章讲解&#xff1a;代码随想录 (programmercarl.com) 视频讲解&#xff1a;贪…

CPU核心数、线程数都是什么意思?

最早&#xff0c;每个物理 cpu 上只有一个核心&#xff0c;对操作系统而言&#xff0c;也就是同一时刻只能运行一个进程/线程。 为了提高性能&#xff0c;cpu 厂商开始在单个物理 cpu 上增加核心&#xff08;实实在在的硬件存在&#xff09;&#xff0c;也就出现了多核 cpu&…

个人博客项目笔记_07

写文章 写文章需要 三个接口&#xff1a; 获取所有文章类别 获取所有标签 发布文章 1. 所有文章分类 1.1 接口说明 接口url&#xff1a;/categorys 请求方式&#xff1a;GET 请求参数&#xff1a; 参数名称参数类型说明 返回数据&#xff1a; {"success":…

Linux启动流程,常见故障英文总结/Linux学习环境发行版本选择及运行故障(补充)

小编这里对前面文章内容进行补充 1.运维架构人员理解Linux启动流程&#xff08;对故障进行排查&#xff09;&#xff0c;企业面试面试官让面试者描述Linux启动细节&#xff0c;小编在这篇文章补充以下&#xff0c;制作了图表&#xff0c;有利于大家看懂整个流程 2.对于初学者/老…

14亿美元!德国默克与AI生物科技公司合作;马斯克Neuralink首位脑机接口植入者用意念打游戏;黄仁勋在俄勒冈州立大学开讲

AI for Science 的新成果、新动态、新视角—— 日本第一 IT 公司富士通&#xff1a;生成式 AI 加速药物研发 马斯克&#xff1a;Neuralink 首位脑机接口植入者用「意念」打游戏 默克与 AI 生物科技公司 Caris 达成合作 AI 蛋白质设计服务提供商「天鹜科技」完成数千万元 Pre…

IDEA中使用正则表达式替换时间日期

很多时候需要把系统中的时间替换成当前时间&#xff0c;这是后我们就可以把数据库SQL文件在IDEA中打开&#xff0c;然后使用正则进行替换&#xff0c;下面我们来看下&#xff1a; 1.日期格式&#xff1a;校验yyyy&#xff0d;MM&#xff0d;dd ((([0-9]{3}[1-9]|[0-9]{2}[1-9…

ELK 企业级日志分析 ELFK

一 ELK 简介 ELK平台是一套完整的日志集中处理解决方案&#xff0c;将 ElasticSearch、Logstash 和 Kiabana 三个开源 工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 1 ElasticSearch&#xff1a; 是基于Lucene&#xff08;一个全文检索引擎的…

golang的引用和非引用总结

目录 概述 一、基本概念 指针类型&#xff08;Pointer type&#xff09; 非引用类型&#xff08;值类型&#xff09; 引用类型&#xff08;Reference Types&#xff09; 解引用&#xff08;dereference&#xff09; 二、引用类型和非引用类型的区别 三、golang数据类型…

李沐27_含并行连结的网络GoogLeNet_Inception——自学笔记

Inception块 1.四个路径从不同层面抽取信息&#xff0c;然后在输出通道维合并。 2.有更少的参数个数和计算复杂度&#xff08;相比于3X3和5X5卷积层&#xff09; GoogLeNet 1.五个stages&#xff0c;九个inception块 Inception各种后续变种 1.Inception-BN(V2)——使用ba…

【Harbor】harbor.yml详解

目录 前言参数详解hostnameHTTP和HTTPSinternal_tlsharbor_admin_passworddatabasedata_volumestorage_serviceclairtrivyjobservicenotificationchartlog_versionexternal_databaseexternal_redisuaaproxy 前言 网络上对Harbor相关的资料真是少之又少&#xff0c;基本上都是教…

2024mathorcup数学建模A 题思路分析-移动通信网络中 PCI 规划问题

# 1 赛题 A 题 移动通信网络中 PCI 规划问题 物理小区识别码(PCI)规划是移动通信网络中下行链路层上&#xff0c;对各覆盖 小区编号进行合理配置&#xff0c;以避免 PCI 冲突、 PCI 混淆以及 PCI 模 3 干扰等 现象。 PCI 规划对于减少物理层的小区间互相干扰(ICI)&#xff0c;增…

STM32程序 关于Semhosting(半主机)和Microlib 以及Printf的关系

一&#xff0c;Keil中Printf导致程序无法运行到Main函数 在Keil中调试STM32程序&#xff0c;编译烧录后&#xff0c;发现程序不能运行&#xff0c;Main函数中点亮LED灯的语句没起作用&#xff0c;说明没有进入Main函数。用Keil调试的时候&#xff0c;虽然设置了Run to main()&…