算法设计与分析实验报告c++java实现(矩阵链连乘、投资问题、完全背包问题、旅行商问题、数字三角形)

news2024/11/25 23:36:56

一、 实验目的

1.加深学生对算法设计方法的基本思想、基本步骤、基本方法的理解与掌握;

2.提高学生利用课堂所学知识解决实际问题的能力;

3.提高学生综合应用所学知识解决实际问题的能力。

二、实验任务

用动态规划算法实现:

1、矩阵链连乘问题 img 2、 投资问题 img3、求解完全背包问题
问题描述:有n种重量和价值分别为wivi(1≤in)的物品,从这些物品中挑选总重量不超过W的物品,求出挑选物品价值总和最大的挑选方案,这里每种物品可以挑选任意多件。

4、旅行商问题
旅行商问题(TSP)又称旅行推销员问题、货郎担问题,它是数学领域中的著名问题之一。假设有一个旅行商人要访问n个城市,这n个城市是一个完全图。他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径选择目标是使求得的路径长度为所有路径之和中的最小值。

5、数字三角形 img

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

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

实验设备:Win10 电脑
开发工具:Visual Studio 2019
编程语言:C/JAVA

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

(一)、矩阵连乘问题

1、算法分析:
(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)。由于只知道链的长度,因此有多个乘法问题,因此我们需要求解出所有乘法问题的最小代价。

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[]代表矩阵链,其中p0、p1为第一个矩阵的行和列
//对矩阵链p求解最佳组合方法,传入矩阵链和元素个数
void MATRIX_CHAIN_ORDER(int p[], int n) {
	for(int i = 1; i <= n; i++) m[i][i] = 0;    //子问题链长为1,代价为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;
				}
			}
		}
	}
}
//利用表s输出从start乘到ends的最优方案
void PRINT_OPTIMAL_PARENS(int s[][N], int start, int 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");
	scanf("%d",&number);
	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");
	return 0;
}


矩阵连乘问题
1、实验结果

img

2、算法复杂度分析
时间复杂度:O(nnn)

(二)、投资问题

1、算法分析:
(1)只考虑第一个项目,即将所有的资金都投资给该项目,那么此时可以获取的利益可以计算出来;
(2)将第二个项目加进去,即投资的资金可以同时分配给两个项目,那么此时可以获取的利益可以计算出来;
(3)将第三个项目加进去,即投资的资金可以同时分配给三个项目,同样可以用上述方法得到此时能获取的利益。
后面以此类推。

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、实验结果

img

2、算法复杂度分析
时间复杂度: O(mnn)

(三)、完全背包问题

1、算法分析:
a) 把背包问题抽象化(X1,X2,…,Xn,其中Xi取0或1,表示第i个物品选或不选),Vi表示第i个物品的价值,Wi表示第i个物品的体积(重量);
b)建立模型,即求max(V1X1+V2X2+…+VnXn);
c)约束条件,W1X1+W2X2+…+WnXn<capacity;
d)定义V(i,j):当前背包容量j,前i个物品最佳组合对应的价值;
e)最优性原理是动态规划的基础,最优性原理是指“多阶段决策过程的最优决策序列具有这样的性质:不论初始状态和初始决策如何,对于前面决策所造成的某一状态而言,其后各阶段的决策序列必须构成最优策略”。

2、代码实现:

import numpy as np
# range(10)等于[0,1,2,3,4,5,6,7,8,9]
# range(1,10)等于[1,2,3,4,5,6,7,8,9]
# range(1,10,2)等于[1,3,5,7,9]
def main(number, bag_weight, weightList, valueList):
    fk = [[0 for j in range(bag_weight + 1)] for i in range(number + 1)]
    # 构造一个list(有number+1个元素,从0到number),其中每个元素也是一个list
    # 并用0初始化,fk用来存放物品i取出的件数
    valueExcel = [[0 for j in range(bag_weight + 1)] for i in range(number + 1)]
    # valueExcel用来存放前i个物品中选出重量不超过j的物品总价值
    for i in range(1, number + 1):
        for j in range(1, bag_weight + 1):
            for k in range((j // weightList[i-1])+1):
                # 因为是list,第i个物品下标为i-1
                if valueExcel[i][j] < (valueExcel[i - 1][j - k * weightList[i-1]] + k * valueList[i-1]):
                    valueExcel[i][j] = (valueExcel[i - 1][j - k * weightList[i-1]] + k * valueList[i-1])
                    fk[i][j] = k
                # 遍历第i个物品的所有可能取值件数
    print(np.array(valueExcel).reshape(number+1,-1))
    # 改变输出形式
    print(np.array(fk).reshape(number + 1, -1))

if __name__=="__main__":
    print("请输入共有多少物品:", end=" ")
    number = int(input())

    print("请输入每个物品的价值:", end=" ")
    valueList = list(map(int, input().split()))
    # a = "1 2 3 4"
    # print(list(map(int, a.split())))
    # [1, 2, 3, 4]
    # a.split()
    # 表示把a字符串按照逗号切分成多个字符串存在一个列表中
    # map(int, a.split())
    # 表示把切分出的列表的每个值, 用int函数把它们转成int型, 并返回迭代器
    # list(map(int, a.split()))
    # 表示用list函数把map函数返回的迭代器遍历展开成一个列表

    print("请输入每个物品的重量:", end=" ")
    weightList = list(map(int, input().split()))

    print("请输入背包重量", end=" ")
    bag_weight = int(input())

main(number, bag_weight, weightList, valueList)

完全背包问题
1、实验结果

img

2、算法复杂度分析
时间复杂度:0(n^3)

(四)、旅行商问题

1、算法分析:
假定从城市1出发,经过了一些地方,并到达了城市j。毋庸置疑,我们需要记录的信息有当前的城市j。同时我们还需要记录已经走过的城市的集合。同理,使用S记录未走过的城市的集合也可以的,且运算方便。
于是可以得出状态转移方程 go(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、代码实现:

package algorithm;

public class TravelingSalesman 
    public static void main(String[] args) {
        int cityCount = 4;
        int[][] roadInfo = new int[][]{
                {0, 1, 62},{1, 0, 65},{1, 3, 64},
                {3, 1, 35},{3, 2, 16},{2, 3, 25},
                {0, 2, 42},{2, 0, 45},{1, 2, 29},
                {2, 1, 45} };

        int roadmap[][] = new int[cityCount][cityCount];        //转成邻接矩阵方便取数
        int dp[][] = new int[cityCount][1 << (cityCount - 1)];
        //String path[][] = new String[cityCount][1 << (cityCount - 1)];
        for (int i = 0; i < cityCount; i++) {
            for (int j = 0; j < cityCount; j++) {
                roadmap[i][j] = 0x7ffff;                        //用0x7ffff表示无穷大
            }
        }
        for (int i = 0; i < roadInfo.length; i++) {                 //邻接矩阵
            roadmap[roadInfo[i][0]][roadInfo[i][1]] = roadInfo[i][2];
        }

        for (int i = 0; i < cityCount; i++) {                          //先求dp表第一列
            dp[i][0] = roadmap[i][0];                            //求出了每个城市回到起点的距离了。
            //记录初始路径。
        }

        for (int j = 1; j < 1 << (cityCount - 1); j++) {             //再求其他列
            for (int i = 0; i < cityCount; i++) {                    //从i出发,要去包含j = {010101}的    城市
                dp[i][j] = 0x7ffff;
                if (((j >> (i - 1)) & 1) == 1) {                   //如果已经到过j了,就continue
                    continue;
                }
                for (int k = 1; k < cityCount; k++) {                 //看能不能先到k城市
                    if (((j >> (k - 1)) & 1) == 0) {
                        continue;                                 //不能先到k城市,continue;
                    }
     if (dp[i][j] > roadmap[i][k] + dp[k][j ^ (1 << (k - 1))]) {
          dp[i][j] = roadmap[i][k] + dp[k][j ^ (1 << (k - 1))];
              //path[i][j] = i + path[k][j ^ (1 << (k - 1))]; //找到更短路径,覆盖之前结果。
                    }
                }
            }
        }
        System.out.println(dp[0][(1 << (cityCount - 1)) - 1]);
        //System.out.println(path[0][(1 << (cityCount - 1)) - 1]);
        System.out.println("                                    动态规划表如下表所示");
        System.out.printf("%10d", 0);
        for (int j = 0; j < 1 << (cityCount - 1); j++) {
            System.out.printf("%10d", j);
        }
        System.out.println();
        for (int i = 0; i < cityCount; i++) {
            System.out.printf("%10d", i);
            for (int j = 0; j < 1 << (cityCount - 1); j++) {
                if (dp[i][j] == 0x7ffff) dp[i][j] = -1;
                System.out.printf("%10d", dp[i][j]);
            }
            System.out.println();

        }
    }
}

旅行商问题
1、实验结果

img

img2、算法复杂度分析
时间复杂度: n*2^(n-1)。

(五)、数字三角形

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>
#include<stdio.h>

int main()
{
	int n, a[101][101], d[101][101], i, j;
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	for (j = 1; j <= i; j++)
		scanf("%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、实验结果

img

2、算法复杂度分析
时间复杂度:0(n^2)

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

通过实现动态规划的题目,对动态规划有了更深的了解。动态规划算法是由单阶段的决策最优逐步转化为多阶段的决策最优,最后构造一个最优解。此次实验的Python代码部分由小组成员提供,每个人感兴趣的语言不一样,但是我们要做到能理解读懂,互相学习,相互提高。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

防火墙操作!

当小编在Linux服务器上部署好程序以后&#xff0c;但是输入URL出现下述情况&#xff0c;原来是防火墙的原因&#xff01;&#xff01; 下面是一些防火墙操作&#xff01; 为保证系统安全&#xff0c;服务器的防火墙不建议关闭&#xff01;&#xff01; 但是&#xff0c;我们可…

idea(2023.1.3)配置全局Maven环境

问题来源一&#xff1a; 1、每次在下载依赖时&#xff0c;会遇到这样的报错信息&#xff0c;报错信息如下显示&#xff1a;sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid cert&#xff1b;百度结果是&#xff1a;通常表示IntelliJ IDEA …

第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组A-E题(go、java实现)

第十四届蓝桥杯大赛软件赛省赛C/C 大学 B 组 A题&#xff1a;日期统计B题&#xff1a;01串的熵C题&#xff1a;冶炼金属D题&#xff1a;飞机降落E题&#xff1a;接龙数列 A题&#xff1a;日期统计 直接遍历2023年每一天&#xff0c;看数组中是否有符合的 java的coding如下&…

【Shell】各种条件语句的使用——test语句、if语句、case语句

Shell条件语句的使用 条件语句 Shell条件语句的使用条件测试的语法字符串测试表达式整数二元比较操作符逻辑操作符 if的条件语句的语法if的嵌套case语句语法 条件测试的语法 语法1&#xff1a;test <测试表达式> 利用test命令进行条件测试表达式的方法。test命令与<测…

【操作系统】段描述符、全局描述符表和选择子

一、保护模式的内存寻址过程 与实模式不同的是&#xff0c;保护模式下内存段不再是简单地用段寄存器加载一下段基址然后乘以16位结合偏移地址得出实际要访问的内存地址&#xff0c;而是通过选择子在全局描述符表中找到对应的段描述符&#xff0c;CPU从段描述符中提取段基址&…

vscode 重命名很慢或失败 vscode renames are slow

网上问题&#xff0c; 插件问题&#xff08;我遇见的排除&#xff0c;不是&#xff09;被其他程序占用问题&#xff0c;&#xff08;我这边是这个&#xff09; 解决方案&#xff1a; 打开【资源管理器】&#xff0c;使用火绒 或其他软件&#xff0c;查看文件夹 or 文件 被哪个…

2024.4.9-day12-CSS 常用样式属性和字体图标

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 作业 作业 <!DOCTYPE html> <html lang"zh-CN"><he…

C++进阶之路---何为智能指针?

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、为什么需要智能指针&#xff1f; 下面我们先分析一下下面这段程序有没有什么内存方面的问题&#xff1f;提示一下&am…

通过系统防火墙,禁用同网段主机互访

要通过系统防火墙禁止同网段主机之间的互访&#xff0c;您可以在Windows操作系统中使用高级防火墙规则来实现。以下是在Windows环境中创建一条规则以阻止本地同一子网内的计算机互相访问的基本步骤&#xff1a; 对于Windows防火墙&#xff08;适用于Windows 7至Windows 11&…

一文带你全面了解功能安全软件监控方案

引言&#xff1a;功能安全标准&#xff08;ISO26262 Part6&#xff09;提到了用于错误探测的安全机制&#xff0c;其中就有程序流监控&#xff0c;如图1所示&#xff1b;本文主要探讨在AUTOSAR CP以及AP的场景下&#xff0c;怎么实现程序流监控。 图1 ISO26262 Part6 一、CP场…

Android设备使用DS file远程访问群晖NAS管理本地文件

文章目录 1. 群晖安装Cpolar2. 创建TCP公网地址3. 远程访问群晖文件4. 固定TCP公网地址5. 固定TCP地址连接 DS file 是一个由群晖公司开发的文件管理应用程序&#xff0c;主要用于浏览、访问和管理存储在群晖NAS&#xff08;网络附加存储&#xff09;中的文件。这个应用程序具有…

JS--demo实现随机点名

逻辑就是通过点击事件得到数组里面的随机一个值&#xff0c;再把这个值给删除&#xff0c;当数组长度为1的时候&#xff0c;停止点名&#xff0c;用disabled属性让用户不能进行点击。 <!DOCTYPE html> <html lang"en"><head><meta charset&quo…

基于springboot实现校园资料分享平台系统项目【项目源码+论文说明】

基于springboot实现校园资料分享平台系统演示 摘要 随着信息互联网购物的飞速发展&#xff0c;国内放开了自媒体的政策&#xff0c;一般企业都开始开发属于自己内容分发平台的网站。本文介绍了校园资料分享平台的开发全过程。通过分析企业对于校园资料分享平台的需求&#xff…

电脑微信双开,微信微信多开支持多个微信同时登录,快速切换,方便快捷 电脑最简单的微信双开多开方法 电脑上怎么登录两个微信账号?电脑微信怎么能够双开?

支持多个微信账号同时登录&#xff0c;不限微信登录个数&#xff0c;运行快速&#xff0c;稳定不卡顿 集成所有聊天窗口&#xff0c;一键快捷切换&#xff0c;窗口再多也不乱&#xff0c;提高你的工作效率 同时管理多个微信号&#xff0c;且需要分别维护用户关系、粉丝社群 …

Oracle表空间满清理方案汇总分享

目录 前言思考 一、第一种增加表空间的数据文件数量达到总容量的提升 二、第二种解决方案针对system和sysaux的操作 2.1SYSTEM表空间优化 2.2sysaux表空间回收 2.2.1针对sysaux的表空间爆满还有第二套方案维护 三、第三种解决方案使用alter tablespace resize更改表空间的…

HTML转EXE工具(HTML App Build)永久免费版:24.4.9.0

最新版本的HTML2EXE即将发布了。自从去年发布了HTML2EXE之后&#xff0c;我就正式上班了&#xff0c;一直忙于工作&#xff0c;实在没有时间更新&#xff08;上班时间不能做&#xff09;&#xff0c;很多网友下载使用&#xff0c;反应很好&#xff0c;提出了一些改进的建议&…

Tomcat项目部署spring mvc项目,压测出现的问题

Tomcat项目部署spring mvc项目&#xff0c;压测出现的问题 项目部署&#xff1a;docker部署时候设置的内存是80G&#xff0c;JVM堆内存的初始堆和最大堆设置的内存都是64G 1、压测的时候&#xff0c;并发1000&#xff0c;循环1次 日志显示&#xff1a;堆内存溢出 2、排查出…

蓝桥杯单片机之PCF8591的使用

下文仅仅讲怎么使用。 本文章参考&#xff1a; 【蓝桥杯】PCF8591 A/D D/A转换应用_pcf8591中输出电压2v怎么表示-CSDN博客 蓝桥杯电子类单片机学习三——PCF8591 AD/DA转化器&#xff0c;AT24C02 EEPROM存储器&#xff08;iic驱动&#xff09;_蓝桥杯da转换输出的是什么-CS…

dg_mmld部分复现

Ours ( K ˆ \^{K} Kˆ2)复现结果– Photo&#xff1a;0.9634730538922156 (at Epoch 23) Art&#xff1a;0.8125 (at Epoch 23) Cartoon&#xff1a;0.7713310580204779 (at Epoch 18) 差距在可接受范围内 辅助信息 If you send 作者 an e-mail, 作者 will tell you a URL w…

C/C++中const关键字用法总结

C基础专栏&#xff1a;http://t.csdnimg.cn/4FdOH 目录 1.引言 2.修饰变量 2.1.修饰普通变量 2.2.修饰指针 2.3.修饰对象 3.修饰函数形参 4.修饰函数返回值 5.修饰类成员函数 6.const与constexpr区别 7.总结 1.引言 在面试的过程&#xff0c;面试官经常都会问到const…