算法与程序课程设计——观光铁路

观光铁路

一、任务

跳蚤国正在大力发展旅游业,每个城市都被打造成了旅游景点。

许多跳蚤想去其他城市旅游,但是由于跳得比较慢,它们的愿望难以实现。这时,小C听说有一种叫做火车的交通工具,在铁路上跑得很快,便抓住了商机,创立了一家铁路公司,向跳蚤国王请示在每两个城市之间都修建铁路。

然而,由于小C不会扳道岔,火车到一个城市以后只能保证不原路返回,而会随机等概率地驶向与这个城市有铁路连接的另外一个城市。

跳蚤国王向广大居民征求意见,结果跳蚤们不太满意,因为这样修建铁路以后有可能只游览了3个城市(含出发的城市)以后就回来了,它们希望能多游览几个城市。于是跳蚤国王要求小C提供一个方案,使得每只跳蚤坐上火车后能多游览几个城市才回来。

小C提供了一种方案给跳蚤国王。跳蚤国王想知道这个方案中每个城市的居民旅游的期望时间(设火车经过每段铁路的时间都为1),请你来帮跳蚤国王。

【输入格式】

输入的第一行包含两个正整数n、m,其中n表示城市的数量,m表示方案中的铁路条数。

接下来m行,每行包含两个正整数u、v,表示方案中城市u和城市v之间有一条铁路。

保证方案中无重边无自环,每两个城市之间都能经过铁路直接或间接到达,且火车由任意一条铁路到任意一个城市以后一定有路可走。

【输出格式】

输出n行,第i行包含一个实数ti,表示方案中城市i的居民旅游的期望时间。你应当输出足够多的小数位数,以保证输出的值和真实值之间的绝对或相对误差不超过1e-9。

二、要求

对于10%的测试点,n <= 10;
对于20%的测试点,n <= 12;
对于50%的测试点,n <= 16;
对于70%的测试点,n <= 19;
对于100%的测试点,4 <= k <= n <= 21,1 <= u, v <= n。数据有梯度。
资源约定:
峰值内存消耗 < 256M
CPU消耗  < 2000ms

摘要:

本算法与程序课程设计通过图论的方法解决了一个实际问题——计算铁路网络中每个城市居民旅游的期望时间。首先,我们根据城市的铁路连接构建了一个有向图模型,并计算了每个城市的出度,这表示了从一个城市出发到其他城市的直接路径数量。通过分析火车运行的规则——即到达一个城市后随机等概率地向任一相连的城市移动且不返回原路。我们为每个城市建立了一个线性方程,表达了基于相邻城市的期望时间计算当前城市的期望时间的关系。这些方程共同形成了一个线性方程组,其解即为各城市居民旅游的期望时间。最终,我们以高精度格式输出了每个城市的期望旅游时间,确保结果的高准确性。此设计不仅展示了复杂系统建模的能力,也体现了算法在解决现实世界问题中的应用价值。

关键字:图论;系统建模;铁路网络;期望旅游时间

三、系统方案

1、任务要求及算法分析

任务要求:
  1. 图构建:根据提供的城市连接数据,构建一个有向图,以模拟铁路网络。每个节点代表一个城市,每个有向边代表两个城市间的铁路连接。
  2. 出度计算:对于图中的每个节点,计算其出度,即从该节点出发的边的数量。这表示从一个城市可以直达的其他城市的数量。
  3. 方程建立:根据火车运行规则,为网络中的每个城市建立一个方程,表达该城市的平均旅游时间与其邻居城市平均旅游时间的关系。确保考虑火车不会沿原路返回的条件。
  4. 求解方程组:使用适当的数学方法,求解由所有城市方程构成的线性方程组。确保计算结果满足精度要求。
  5. 结果输出:将每个城市的期望旅游时间以指定的格式输出。
解题思路: 

 对于出发点城市1来说,出发到每个子节点的概率之和(出度)与父节点到本节点的概率之和

(入度)相等,且为1。也就是说,乘客一定会回到起点。

对于概率p1 , p2 … … pn 与相对应的值x1 , x2 … … xn

它们的平均期望应该是

这个平均期望对应的概率是

对于某个节点K

到达K的平均期望就是\overline{x}

到达K的概率就是p

算法分析:

时间复杂度: 主要的时间消耗主要体现在两个循环结构的执行上:第一个循环结构用于读取输入数据,并统计每个节点的度数。这个循环结构的时间复杂度为O(m),因为需要遍历所有的边。第二个循环结构用于计算每个节点的平均度数,并输出结果。这个循环结构的时间复杂度为O(n),因为需要遍历所有的节点。时间复杂度为O(m+n)。

空间复杂度: 空间复杂度是O(n),其中n表示节点数。因为代码中使用了一个长度为MAX的数组num来存储每个节点的度数,而节点数最多为n。

数值稳定性: 在计算过程中需注意数值的稳定性和精度问题。

2、方案比较与选择

  1. 方案一:使用SPFA算法
    • 优点:时间复杂度较低,适用于大规模图的处理。
    • 缺点:不能保证得到全局最优解,可能产生冗余操作。
  2. 方案二:使用Dijkstra算法
    • 优点:能够保证得到全局最优解,适用于无负权边的图。
    • 缺点:时间复杂度较高,不适用于大规模图的处理。
  3. 方案三:通过输入输出案例找规律
    • 优点:代码简短,易于理解。
    • 缺点:不清楚通过规律算时间期望的原因。

 Dijkstra 算法与 SPFA算法比较

1、负权边处理

1. Dijkstra 算法 :不能处理带负权的边。
2. SPFA 算法 :可以处理带负权的边。
2、 算法原理
1. Dijkstra 算法 :使用优先队列(最小堆)来选择下一个要处理的节点,这样可以保证每次选择的都是当前已知最短路径的节点,从而逐步扩展已确定最短路径的节点集合。
2. SPFA 算法 :使用队列这一数据结构,但其核心在于边的遍历和更新。当一个节点的距离估计发生变化时,该节点会重新入队,以便于更新所有相邻节点的距离估计。
3、 时间复杂度
1. Dijkstra 算法 :通常情况下时间复杂度为 O(| V|log|V | + |E|) ,其中 |V| 是节点数量, |E| 是边的数量。每处理一个节点,都要在优先队列中进行插入和删除操作。
2. SPFA 算法 :在最坏情况下时间复杂度为 O(|V||E|) ,但实际表现通常好于这个界限,特别是在稀疏图或者边权为整数的情况下。

 

代码实现:
#include <iostream>
#include <vector>
#include <queue>
#include <iomanip>
using namespace std;

const int INF = 1e9;

int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> edges(m, vector<int>(2));
    vector<vector<int>> dist(n, vector<int>(n, INF));
    for (int i = 0; i < m; ++i) {
        cin >> edges[i][0] >> edges[i][1];
        dist[edges[i][0] - 1][edges[i][1] - 1] = 1;
        dist[edges[i][1] - 1][edges[i][0] - 1] = 1;
    }
    vector<int> in_degree(n, 0);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (dist[i][j] != INF) {
                in_degree[j]++;
            }
        }
    }
    queue<int> q;
    for (int i = 0; i < n; ++i) {
        if (in_degree[i] == 0) {
            q.push(i);
        }
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int v = 0; v < n; ++v) {
            if (dist[u][v] != INF) {
                dist[u][v] = min(dist[u][v], dist[u][u] + dist[u][v]);
                in_degree[v]--;
                if (in_degree[v] == 0) {
                    q.push(v);
                }
            }
        }
    }
    for (int i = 0; i < n; ++i) {
        double sum = 0;
        for (int j = 0; j < n; ++j) {
            if (dist[i][j] != INF) {
                sum += dist[i][j];
            }
        }
        cout << fixed << setprecision(10) << sum / (n - 1) << endl;
    }
    return 0;
}
发现规律:

四、算法实现

1、算法流程设计

  1. 初始化一个长度为MAX的整型数组num,用于存储每个节点的度数。
  2. 从标准输入读取两个整数n和m,分别表示节点的数量和边的数量。
  3. 使用一个for循环,循环m次,每次循环中: a. 从标准输入读取两个整数u和v,表示一条边连接的两个节点。 b. 将num[u]和num[v]的值加1,表示这两个节点的度数都增加了1。
  4. 使用另一个for循环,循环n次,每次循环中: a. 计算当前节点的度数概率p,公式为:p = m * 2.0 / num[i]。 b. 使用printf函数,以保留12位小数的格式输出p。
  5. 返回0,表示程序正常结束。

2、算法模型构建

根据提供的城市连接数据,构建一个有向图,以模拟铁路网络。每个节点代表一个城市,每个有向边代表两个城市间的铁路连接。使用图论中的最短路径算法来计算从任一城市出发到达其他城市的最短路径长度。

完整代码:

#include<iostream>
using namespace std;
const int MAX = 100;
int num[MAX];

int main()
{
	int n, m,i;
	cin >> n >> m;
	for (i = 1; i <= m; i++)
	{
		int u, v;
		cin >> u >> v;
		num[u]++;
		num[v]++;
	}
	for (i = 1; i <= n; i++)
	{
		double p = m * 2.0 / num[i];
		printf("%.12f\n", p);
	}
	return 0;
}

时间复杂度: 主要的时间消耗主要体现在两个循环结构的执行上:第一个循环结构用于读取输入数据,并统计每个节点的度数。这个循环结构的时间复杂度为O(m),因为需要遍历所有的边。第二个循环结构用于计算每个节点的平均度数,并输出结果。这个循环结构的时间复杂度为O(n),因为需要遍历所有的节点。

时间复杂度:O(m+n)

空间复杂度O(n),其中n表示节点数。

五、工程管理及经济学分析

1、算法实现所涉及的工程管理

  1. 项目管理
    • 项目规划:制定算法实现铁路建设计划,包括城市间铁路的数量、长度和连接方式。
  2. 团队协作
    • 沟通协调:建立有效的沟通机制,确保团队成员之间的信息流通。
    • 任务分配:根据团队成员的能力和特长,合理分配任务,提高工作效率。
    • 冲突解决:及时解决团队内部的矛盾和冲突,维护良好的团队氛围。
  3. 进度管理
    • 进度计划:制定详细的进度计划,确保项目按时完成。
    • 进度跟踪:实时跟踪工程进度,及时发现并解决影响进度的问题。
    • 进度调整:根据实际情况,适时调整工程进度计划,确保项目顺利进行。

注意事项:

  • 数据准确性:输入数据的准确性至关重要,任何错误都可能导致算法结果的偏差。
  • 算法效率:考虑到大规模的城市数量,算法的效率必须足够高。
  • 结果精确度:输出的结果应保证足够的小数位数,以满足误差不超过1e-9的要求。

2、算法实现中体现的经济学分析

  1. 成本效益分析:在规划铁路网络时,需要对比建设和维护铁路的成本与通过提升旅游效率带来的收益。包括直接收益(如票价收入)和间接收益(如增加的就业机会、促进当地经济发展等)。
  2. 需求预测:对旅游需求进行预测,了解不同城市间的旅客流量,以及旅游高峰期和淡季的变化。有助于设计出能够满足不同时间段需求的铁路服务。
  3. 外部性:考虑铁路建设和运营可能带来的正面或负面外部效应,例如减少交通拥堵、环境污染,或者提高地区间的经济联系。

 六、总结

1、过程难点及反思

1. 理解问题需求

难点:在课程设计的初期,难以完全理解问题背景和需求。
反思:应该采用多种方式(如流程图)确保对需求有清晰的认识。

2. 选择合适的数据结构和算法

难点:面对复杂问题时,确定最合适的数据结构和算法是一大挑战,尤其是在性能和实现复杂度之间需要权衡。
反思:应通过学习,加强对不同数据结构和算法性能的了解。

3. 编码实现

难点:将设计好的算法转化为实际代码时,会遇到语法错误、逻辑错误等问题。
反思:编写单元测试来验证每个函数的正确性,逐步集成各个模块。

2、心得与体会 

1. 理解问题的复杂性

深度分析 :在课程设计之初,我意识到了深入分析问题的重要性。仅仅表面上的理解会导致解决方案的偏差。
层层递进 :通过逐步分解问题,我更加清晰地看到了问题的本质,这有助于构建更加精确的算法模型。

2. 数据结构与算法的选择

权衡比较 :选择合适的数据结构和算法是关键步骤,我学会了如何根据问题特点进行权衡比较。
持续学习 :这一过程也让我明白了学习新算法和数据结构是一个不断的、终身的过程。

3. 编码实现的挑战

细节关注 :编码过程中,我更加注意到了细节对程序性能和稳定性的影响。
重构优化 :不断重构和优化代码,我体会到了简洁代码带来的高效维护和易于理解的好处。

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

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

相关文章

Kubernetes proxy 命令与集群资源交互中起的作用

关于 Kubernetes 中的 kubectl proxy 命令&#xff0c;理解它的作用有助于更深入地掌握 Kubernetes 如何管理集群内的资源&#xff0c;以及开发和调试时如何通过代理来简化交互。kubectl proxy 提供了一种安全且方便的方式来访问 Kubernetes API 服务器&#xff0c;尤其是在调试…

今日指数day8实战补充(上)

1.用户管理 1.多条件综合查询 1.1 多条件综合查询接口说明 1&#xff09;原型效果 2&#xff09;接口说明 功能描述&#xff1a;多条件综合查询用户分页信息&#xff0c;条件包含&#xff1a;分页信息 用户创建日期范围 服务路径&#xff1a;/api/users 服务方法&#xff1…

用Manim简单解释奇异值分解(SVD)和图像处理方面的应

一&#xff0c;介绍 奇异值分解&#xff08;SVD&#xff09;是一种重要的矩阵分解技术&#xff0c;在统计学、信号处理和机器学习等领域有广泛应用。对于任意给定的矩阵 A&#xff08;可以是任意形状的矩阵&#xff09;&#xff0c;SVD将其分解为三个特定的矩阵的乘积&#x…

idea2024设置中文

今天下载idea2024.2版本&#xff0c;发现已经装过中文插件&#xff0c;但是还是不显示中文&#xff0c;找了半天原来还需要设置中文选项 方案一 点击文件 -> 关闭项目 点击自定义 -> 选择语言 方案二 点击文件 -> 设置 外观与行为 -> 系统设置 -> 语言和地区…

LSTM时序预测 | Python实现LSTM长短期记忆神经网络时间序列预测

本文内容&#xff1a;Python实现LSTM长短期记忆神经网络时间序列预测&#xff0c;使用的数据集为AirPassengers 目录 数据集简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 数据集简介 AirPassengers 数据集的来源可以追溯到经典的统计和时间序列分析文献。原始数据集由 Box,…

增强分析:新时代的数据洞察工具

随着数据科学和人工智能的迅猛发展&#xff0c;分析数据的方式也发生了显著的变化。增强分析&#xff08;Augmented Analytics&#xff09;是近年来涌现出的新概念&#xff0c;它将人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&#xff09;和自然语言处理&…

HarmonyOS NEXT - 表单录入组件封装(TextInput)

demo 地址: https://github.com/iotjin/JhHarmonyDemo 组件对应代码实现地址 代码不定时更新&#xff0c;请前往github查看最新代码 HarmonyOS NEXT - 表单录入组件封装&#xff08;TextInput&#xff09; 序JhFormInputCellJhFormSelectCellJhLoginTextField 序 鸿蒙next中有两…

java 的三种IO模型(BIO、NIO、AIO)

java 的三种IO模型&#xff08;BIO、NIO、AIO&#xff09; 一、BIO 阻塞式 IO&#xff08;Blocking IO&#xff09;1.1、BIO 工作机制1.2、BIO 实现单发单收1.3、BIO 实现多发多收1.4、BIO 实现客户端服务端多对一1.5、BIO 模式下的端口转发思想 二、NIO 同步非阻塞式 IO&#…

Android15车载音频之Virtualbox中QACT实时调试(八十八)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

Pikachu- Over Permission-垂直越权

以admin 账号登陆&#xff0c;添加一个用户&#xff1b; 把添加用户的这个请求发送到 repeater&#xff1b; 退出admin&#xff0c;使用普通用户pikachu登陆&#xff1b; 只有查看权限&#xff1b; 使用pikachu 用户的认证信息&#xff0c;替换repeater处管理员创建用户请求的…

六、索引的数据结构

文章目录 1. 为什么使用索引2. 索引及其优缺点2.1 索引概述2.2 优点2.3 缺点3. InnoDB中索引的推演3.1 索引之前的查找3.1.1 在一个页中的查找3.1.2 在很多页中查找3.2 设计索引3.2.1 一个简单的索引设计方案3.2.2 InnoDB中的索引方案3.3 常见索引概念3.3.1 聚簇索引3.3.2 二级…

UDP协议【网络】

文章目录 UDP协议格式 UDP协议格式 16位源端口号&#xff1a;表示数据从哪里来。16位目的端口号&#xff1a;表示数据要到哪里去。16位UDP长度&#xff1a;表示整个数据报&#xff08;UDP首部UDP数据&#xff09;的长度。16位UDP检验和&#xff1a;如果UDP报文的检验和出错&…

centos一些常用命令

文章目录 查看磁盘信息使用 df 命令使用 du 命令 查看磁盘信息 使用 df 命令 df&#xff08;disk free&#xff09;命令用于显示文件系统的磁盘空间占用情况。 查看所有挂载点的磁盘使用情况&#xff1a; df -h选项说明&#xff1a; -h 参数表示以人类可读的格式&#xff0…

Windows下Jenkins控制台中文乱码

问题描述 问题情况如下图&#xff1a; 环境信息 Windows 11 家庭中文版java 21.0.4 2024-07-16 LTSJenkins 2.452.3 解决方法 增加系统JAVA_TOOL_OPTIONS&#xff0c;并设置值为-Dfile.encodingGBK。 打开设置方法&#xff1a;桌面上右键点击“此电脑”图标&#xff0c;选…

【黑马点评】使用RabbitMQ实现消息队列——3.使用Jmeter压力测试,导入批量token,测试异步秒杀下单

3 批量获取用户token&#xff0c;使用jmeter压力测试 3 批量获取用户token&#xff0c;使用jmeter压力测试3.1 需求3.2 实现3.2.1 环境配置3.2.2 修改登录接口UserController和实现类3.2.3 测试类 3.3 使用jmeter进行测试3.4 测试结果3.5 将用户登录逻辑修改回去 3 批量获取用户…

力扣16~20题

题16&#xff08;中等&#xff09;&#xff1a; 思路&#xff1a; 双指针法&#xff0c;和15题差不多&#xff0c;就是要排除了&#xff0c;如果total<target则排除了更小的&#xff08;left右移&#xff09;&#xff0c;如果total>target则排除了更大的&#xff08;rig…

三绕组单相电容电动机的瞬态分析(2)定子三角形接法时起动过程及稳态性能分析

1. 引言 2. 定子接三绕组单相电容电动机的数学模型 3.最佳移相电容计算 4. 仿真分析实例 5. 总结 6. 参考文献 1. 引言 目前,三相供电系统在全世界范围内已是非常普遍了。但是,由于架设输电线成本高,受输、配电系统的限制,城市居民用电和大多数农村及边远地区的用电仍…

JavaWeb——Vue路由(概述、介绍、使用、解决bug)

目录 概述 介绍 使用 解决bug 概述 员工管理的页面已经制作完成。其他页面的制作方式一致。 项目中准备了部门管理的页面组件 DeptView &#xff0c;这样就有了员工管理和部门管理两个页面组件。 在系统中&#xff0c;要实现点击部门管理菜单展示部门管理组件&#xff0c…

线性代数入门指南

在数学的广袤领域中&#xff0c;线性代数犹如一座神秘而又充满魅力的殿堂&#xff0c;等待着初学者去探索。当你踏入线性代数的大门&#xff0c;便开启了一段充满挑战与惊喜的知识之旅。 线性代数是什么呢&#xff1f;简单来说&#xff0c;它是一门研究线性方程组、向量空间、线…

Android Automotive(一)

目录 什么是Android Automotive Android Automotive & Android Android Automotive 与 Android Auto 什么是Android Automotive Android Automotive 是一个基础的 Android 平台&#xff0c;它能够运行预装的车载信息娱乐系统&#xff08;IVI&#xff09;应用程序&#…