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

news2024/10/8 22:54:32

观光铁路

一、任务

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

许多跳蚤想去其他城市旅游,但是由于跳得比较慢,它们的愿望难以实现。这时,小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. 编码实现的挑战

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

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

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

相关文章

C语言基础(10)之指针(2)

在上一篇文章中我们谈到了指针&#xff0c;并给老铁们讲解了什么是指针、指针类型、野指针以及指针运算等知识。在这篇文章中小编将继续带大家了解指针的相关知识点。 1. 指针和数组 指针和数组之间又能有什么联系呢&#xff1f;在谈这个之前&#xff0c;我们先来讲讲指针和数…

深入分析——为什么未初始化的全局变量是零?

1、前言 #include <stdio.h>int temp;int main(void) {//打印temp的值是零printf("temp%d\n", temp);return 0; }在C语言编程中&#xff0c;我们默认未初始化的全局变量、静态局部变量的初始化值都是零&#xff0c;底层原理如下 未初始化的全局变量、静态局部…

揭秘AI写作工具:如何改变内容创作新格局

小伙伴们&#xff0c;今儿咱们来聊聊那些个让人眼前一亮、脑洞大开的AI写作神器——笔灵AI写作、宙语AI写作、博思白板AI写作&#xff0c;还有讯飞星火&#xff0c;它们啊&#xff0c;简直就是文案人儿的超级辅助&#xff0c;让咱们写东西的时候&#xff0c;灵感嗖嗖地往外冒&a…

TinyOS -数据发布实验

文章目录 简介分析 简介 分发协议主要用于维护网络共享配置的一致性&#xff0c;这里的共享配置可以是节点传感器采样的周期、节点LPL醒睡的周期或者节点运行程序的映像等。每个节点都会维护一份这样的配置&#xff0c;分发协议负责通知每个节点这些配置的改变&#xff0c;并通…

国产分布式数据库开启新篇章!详解安全可靠测评结果公告(2024年第2号)

重磅消息&#xff01;2024年的安全可靠测评结果&#xff08;数据库篇&#xff09;终于揭晓了&#xff01;&#x1f680; 9月30日&#xff0c;国庆前夕&#xff0c;中国信息安全测评中心和国家保密科技测评中心联合发布了今年第二号测评结果&#xff0c;这份名单有效期三年&…

大数据新视界 --大数据大厂之大数据驱动智能客服 -- 提升客户体验的核心动力

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

MATLAB与R语言在建模中的合作与应用(下篇)

目录 目录 模型训练的协同使用 1. 使用 R 语言进行统计建模 2. 使用 MATLAB 进行机器学习建模 模型评估与调优 1. 在 R 中评估模型性能 2. 在 MATLAB 中进行模型优化 实战示例&#xff1a;MATLAB 与 R 的协同建模 总结 在上篇文章中&#xff0c;我们介绍了 MATLAB 和 R…

打工人狂喜,轻松定时发圈

自动定时发圈软件有哪些优势&#xff1f; 1、不用下载安装软件 2、不需要绑定手机或电脑 3、不对电脑或手机做限制 4、不越狱不刷机 5、能更新迭代 6、有售后服务 7、使用安全登录&#xff0c;保障账号安全的 8、不用去做独立部署&#xff08;可以选择&#xff09; 9、…

class 032 位图

这篇文章是看了“左程云”老师在b站上的讲解之后写的, 自己感觉已经能理解了, 所以就将整个过程写下来了。 这个是“左程云”老师个人空间的b站的链接, 数据结构与算法讲的很好很好, 希望大家可以多多支持左程云老师, 真心推荐. 左程云的个人空间-左程云个人主页-哔哩哔哩视频…

重生之我们在ES顶端相遇第 20 章 - Mapping 参数设置大全(进阶)

文章目录 0. 前言1. 前置知识 - _source2. copy_to3. doc_values4. index5. enabled6. normalizer7. null_value8. 总结 0. 前言 在基础篇&#xff0c;我们只介绍了索引 Mapping 的基本用法。 本章将深入探讨日常中较经常使用的 Mapping 其他参数配置。 不想看过程&#xff0c…

Qt 实现动态时钟

1.实现效果 2.widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace

陪护小程序|护理陪护系统|陪护小程序成品

智能化&#xff0c;作为智慧医疗宏伟蓝图的基石&#xff0c;正引领着一场医疗服务的深刻变革。在这场变革的浪潮中&#xff0c;智慧医院小程序犹如璀璨新星&#xff0c;迅速崛起&#xff0c;而陪护小程序的诞生&#xff0c;更是如春风化雨&#xff0c;细腻地触及了老年病患、家…

Spring Cloud Netflix Ribbon 负载均衡详解和案例示范

1. 引言 在传统的集中式架构中&#xff0c;负载均衡器一般是放置在服务器端的&#xff0c;例如 Nginx等。随着微服务架构的兴起&#xff0c;服务实例的数量和部署地点变得更加动态和分布式&#xff0c;这使得在客户端进行负载均衡成为了一种可行且更灵活的方案。Netflix Ribbo…

【Linux】Linux命令与操作详解(二)权限管理、存储管理(磁盘分区、格式化、挂载)、进程管理、yum软件包安装

文章目录 一、前言二、权限管理2.1、用户权限2.2、权限说明2. 3、常用命令1、chmod2、chown3、chgrp 三、存储管理磁盘的分区、格式化与挂载1、新建一块硬盘2、在新建硬盘中进行分区3、格式化4、挂载 四、进程管理进程管理命令1、ps2、top3、nice 五、YUM软件包安装1、修改默认…

算法6:模拟运算

文章目录 z字形变幻外观数列数青蛙 题目均来自于力扣 z字形变幻 class Solution { public:string convert(string s, int numRows) {int n s.size();if(n < numRows || numRows 1) return s;int d 2 * numRows - 2;string res;for(int j 0; j < n; j d){res s[j]; …

Chromium 中<a> 标签href 属性实现分析c++

HTML 链接&#xff08;Anchor&#xff09;是网页之间跳转的核心部分。 HTML 使用链接与网络上的另一个文档相连。 HTML中的链接是一种用于在不同网页之间导航的元素。 链接通常用于将一个网页与另一个网页或资源&#xff08;如文档、图像、音频文件等&#xff09;相关联。 …

如何解决位置在表里的二维码的错行问题

众所周知&#xff0c;sap 里的二维码&#xff0c;在从其他形式转换成二维码之后&#xff0c;会经常有数据位置改变的情况&#xff0c;想让它老老实实待在原地很难&#xff0c; 这里要注意设置行间距&#xff0c;如果行间距不合适&#xff0c;就会导致错位

桥梁检测系统源码分享

桥梁检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision 研究…

Vue入门-指令学习-v-on

v-on 作用&#xff1a;注册事件 添加监听 提供处理逻辑 语法&#xff1a; v-on:事件名"内联语句" v-on:事件名"methods中的函数名" 注意&#xff1a;" v-on&#xff1a;"可以替换为" " v-on:click"XXX" --> cli…

CPU中的寄存器是什么以及它的工作原理是什么?

在计算机科学中&#xff0c;寄存器是数字设备中的一个重要组成部分&#xff0c;它用于存储数据和指令以快速处理。寄存器充当临时存储区&#xff0c;信息可以在这里被快速访问和操作&#xff0c;以执行复杂任务。寄存器是计算机中最基础的存储类型&#xff0c;它们在帮助机器高…