Compare commits

..

No commits in common. 'master' and 'zmy_04-05' have entirely different histories.

@ -1,30 +1,31 @@
# Urban_subway_navigation_system
##城市地铁导航系统 ##
###摘要:本项目针对城市地铁导航系统问题,可实现的功能有:###
城市地铁导航系统
摘要:本项目针对城市地铁导航系统问题,可实现的功能有:
1、输出所有地点及其介绍
2、查询某一个地点及其介绍
3、查询某一地点到其他所有地点的最短路径
4、查询某两个地点之间的最短路径
为有效地存储和处理数据,我们采用了图结构的数据结构。具体来说,我们使用邻接表存储每个站点及其相邻站点的信息,并使用哈希表存储站点名称和编号的映射关系。
为了找出两点间最短路径采用了Dijkstra算法。
项目的效果从整体来看运行流畅,可以为市民提供方便、快捷的地铁路线查询和导航服务。
工作量占比:
| 李文菲 | 刘宇婷 | 连桢钰 | 翟梅瑛 |
|---|---|---|---|
| 25 | 25 | 25 | 25 |
## 1. 系统分析
### 1.1 问题描述
3、增加一个地点
4、删除一个地点
5、更新一个地点
6、增加一条路
7、删除一条路
8、更新一条路
9、查询某一地点到其他所有地点的最短路径
10、查询某两个地点之间的最短路径
11、输出地图
*为有效地存储和处理数据,我们采用了图结构的数据结构。具体来说,我们使用邻接表存储每个站点及其相邻站点的信息,并使用哈希表存储站点名称和编号的映射关系。
*为了找出两点间最短路径采用了Dijkstra算法算法效率较高。
*项目的效果从整体来看运行流畅,可以为市民提供方便、快捷的地铁路线查询和导航服务。
*任务分工及工作量占比:(完成情况良好)
| 翟梅瑛 | 连桢钰 | 刘宇婷 | 李文菲 |
| ---- | ---- | ---- | ---- |
| 项目设计 | 代码创建 | 优化改进 | 项目测试 |
| 25% | 25% | 25% | 25% |
1. 系统分析
1.1 问题描述
选择北京地铁,建立地铁站点导航地图,设计一个城市地铁导航系统。根据任意指定的两个站点,能够计算出任意两个站点之间路径长度最短的站点导航,并给出换乘方案。
### 1.2 可行性分析
1.2 可行性分析
1.明确解决问题的关键:城市地铁导航系统主要解决的问题是用户在地铁出行过程中需要查询线路、站点等信息,以及如何计算最短路径、如何显示用户当前位置等问题。
2.确定核心数据结构:城市地铁导航系统的核心数据结构是图,将每个地铁站点看作一个节点,每条地铁线路看作一条有向边,通过节点之间的连接表示地铁线路的走向和路径。使用邻接表或邻接矩阵等数据结构来存储图结构。此外,还需要存储地铁站点的位置、经纬度、名称、所属线路等信息。
3.确定核心算法城市地铁导航系统的核心算法是图论算法主要包括 Dijkstra 算法、贝尔曼-福德算法和 A* 算法等,用于寻找从起点到终点最短路径。同时还需要对地图进行可视化说明,例如显示沿途经过的地铁站点、换乘点和线路等信息。
@ -39,7 +40,7 @@
6其他功能例如公交线路查询、建议路径提醒等增强用户体验的功能。
总的来说,城市地铁导航系统需要综合运用数据库、图论算法、用户界面设计等多种技术和工具,才能实现方便、快速、准确的地铁线路查询和导航功能。
### 1.3 需求分析
1.3 需求分析
1输入和输出
输入:用户希望到达的地铁站、出发地铁站、换乘信息、线路信息等。
 输出:给用户提供最优路径和换乘信息,告知用户需要哪些线路和站点,预计到达时间等。
@ -60,19 +61,18 @@
主要作用:查询某个线路的信息。
 用户输入:线路号。
 系统输出:该线路的信息,包括沿线站点和车站信息、导向信息等。
## 2. 系统设计
### 2.1 概要设计
7地图展示功能
主要作用:在地图上展示各个站点和线路的位置和路线。 
用户输入:无
 系统输出:地铁线路和站点在地图上的显示,方便用户更直观地了解线路位置和路线。
2. 系统设计
2.1 概要设计
系统划分为以下模块:
1.用户输入模块:用户通过输入起始站点和终点站点,触发系统查询和计算。
2.数据存储模块:系统将地铁线路和站点信息存储在一个数据结构中,并提供查询和修改功能。
3.路径计算模块:该模块通过获取用户输入的起始站点和终点站点,并利用存储在数据结 构中的地铁线路和站点信息,计算出最优路径。
4.输出模块:该模块将最优路径输出给用户,以便用户按照路径指引乘坐地铁。
### 2.2 数据结构设计
2.2 数据结构设计
通过比较邻接矩阵、邻接表、查找表和不相交集等数据结构,我们选择使用邻接表作为数据结构。邻接表具有占用空间小、查询速度快等优势,适合储存大量的地铁线路和站点信息。
邻接表
邻接表是一种表示图形的数据结构,它用于描述地铁网络中的站点之间的连接关系。在邻接表中,每个站点对应一个链表,链表中的每个节点表示与该站点相邻的另一个站点。具体而言,我们可以用如下的结构体表示邻接表中的每个节点:
@ -91,240 +91,61 @@ struct Station {
struct Station stations[MAX_STATION_NUM]; // 站点数组
在这个结构中,我们为每个站点记录了它的名称、编号和相邻节点链表的头节点指针。这样的话,我们就可以通过遍历这些链表来获取某一站点的所有邻居站点。同时,由于链表中的每个节点包含了相邻站点的编号和连接权重,因此我们也可以在搜索路径时方便地计算出经过某一条路径的总长度或换乘次数。
### 2.3 算法设计
示意图如下,表示了一个包含 4 个站点和 5 条连接边的地铁网络的邻接表结构:
stations[]:
index 0 1 2 3
+---------+---------+---------+---------+
| name | id | head | |
+---------+---------+---------+---------+
| "PARK" | 0 | +---|-----+ |
+---------+---------+---------+---------+
| "GATE" | 1 | +---|-----+ |
+---------+---------+---------+---------+
| "TOWER" | 2 | +---|-----|--+|
+---------+---------+---------+----|----+
| "HALL" | 3 | +---|-----+ |
+---------+---------+---------+---------+
adj_list[]:
station 0: PARK
head -> O |weight=5| -> 1 |weight=3| -> 2 |weight=1| -> null
station 1: GATE
head -> O |weight=3| -> 0 |weight=4| -> 3 |weight=2| -> 2 |weight=1| -> null
station 2: TOWER
head -> O |weight=1| -> 1 |weight=1| -> 3 |weight=3| -> null
station 3: HALL
head -> O |weight=2| -> 1 |weight=5| -> null
在这个示意图中stations 数组中的每个元素都包含了它所代表的站点的名称、编号和相邻节点链表的头节点指针。例如stations[0] 表示 "PARK" 站,它的编号为 0与相邻的站点是 "GATE"、"TOWER" 和 "HALL"。其中,与 "GATE" 站相连的边的权重为 5与 "TOWER" 相连的边的权重为 3与 "HALL" 相连的边的权重为 1。而对应的 adj_list 数组则记录了每个站点相邻节点链表的具体内容,其中每个节点包含了相邻站点的编号和连接权重。
2.3 算法设计
我们选择Dijkstra算法作为路径计算模块的核心算法。Dijkstra算法是一种广泛应用于最短路径问题上的算法具有速度快、结果正确性高、易于实现等优势。它通过不断更新起点到每个点的最短距离并使用优先队列维护每个点的最短距离直到计算出终点的最短路径。
Dijkstra算法
用户输入起点站和终点站程序使用图论算法在地铁线路图中寻找到两个站之间的一条最短路径。此时使用Dijkstra算法找出最短路径。
## 3. 系统实现##
 系统使用C++语言进行开发使用VScode作为开发工具。
本系统的文件结构如下:
- SubwaySystem
  - include
    - SubwaySystem.h
  - src
    - SubwaySystem.cpp
  - test
    - test.cpp
  - CMakeLists.txt
其中SubwaySystem.h和SubwaySystem.cpp分别实现了地铁系统的数据结构和算法test.cpp实现了测试用例。
以下是主要函数的功能:
void queryAllSite():打印所有的站点及介绍
void querySite():输入所要查询的地点的编号及介绍
void dijkstraAllSite():计算所在地点到所有地点的最佳路径
void printAllSite():打印到所有地点的最短路径长度及路径
void dijkstraTwoSite():计算最短路径
void printTwoSite():输出最短路径总距离,输出所经过的地点路径
main():打印目录页
### 3.1 核心数据结构的实现
数据结构的实现
本系统使用邻接表来表示地铁系统的图。具体实现如下:
struct Node {
    int id; // 节点ID
    string name; // 节点名称
};
struct Edge {
    int from; // 起点ID
    int to; // 终点ID
    int weight; // 权重(距离)
};
    // 计算两个站点之间的最短路径
    vector<Node> shortestPath(Node from, Node to);
private:
    // 存储节点和边的数据结构
    vector<Node> nodes_;
    vector<vector<pair<int, int>>> adjacencyList_;
    // 计算从起点到终点的最短路径
    vector<int> dijkstra(int from, int to);
};
其中SubwaySystem.h和SubwaySystem.cpp分别实现了地铁系统的数据结构和算法test.cpp实现了测试用例。
### 3.2 核心算法的实现
 系统的核心算法主要包括最短路径算法和站点搜索算法。
最短路径算法采用Dijkstra算法实现该算法的时间复杂度为O(n^2)其中n为站点数。具体实现方式如下
1.初始化距离dist和最短路径标记visited数组。
2.将起点的距离dist设为0将visited标记设为false。
3.对于每个未标记的站点找出距离起点最近的站点v。
4.将v标记为已访问对于v的每个邻居站点u如果dist[u]>dist[v]+v到u的距离更新dist[u]为dist[v]+v到u的距离。
5.重复以上步骤,直到所有站点都被标记为已访问或者没有可访问的站点。
站点搜索算法采用DFS算法实现该算法的时间复杂度为O(n^2)其中n为站点数。具体实现方式如下
1.初始化visited数组。
2.从起点出发,采用深度优先搜索方式,访问所有邻居站点。
3.将访问过的站点标记为visited。
4.重复以上步骤,直到找到终点或者没有可访问的站点。
通过以上算法的实现,我们可以实现在地铁图中查找两个站点之间最短路径和查找某个站点的所有邻居站点。
## 4.系统测试
1输入1
结果:输出了所有的站点及简略介绍
```c++
请输入选项1
所有地点如下:
编号; 1
地点:苹果园
介绍:北京市石景山区,位于苹果园南路
编号; 2
地点:古城
介绍:位于北京市石景山区石景山路与古城小街交会东侧
编号; 3
地点:八角游乐园
介绍:石景山区八角立交桥东侧
编号; 4
地点:公主坟
介绍:北京市海淀区复兴路和西三环中路交会处下方
编号; 5
地点:复兴门
介绍:位于北京市西城区复兴门外大街、复兴门内大街、复兴门南大街、复兴门北大街交汇处
编号; 6
地点:天安门西
介绍位于中国北京市西城区西长安街和南长街交会处是北京地铁运营有限公司运营管理的车站也是北京地铁1号线的中间站
编号; 7
地点:建国门
介绍位于中国北京市东城区与朝阳区交界处建国门桥下方是北京地铁运营有限公司运营的车站也是北京地铁1号线、北京地铁2 号线的换乘站
编号; 8
地点:永安门
介绍:位于中国北京市朝阳区建国门外大街与东大桥路交叉口的下方
编号; 9
地点:鼓楼大街
介绍是北京地铁2号线与北京地铁8号线的换乘站,位于北京市西城区与东城区交界处,安定门西大街-德胜门东大街与旧鼓楼大街-旧 鼓楼外大街交会处
编号; 10
地点:雍和宫
介绍:位于北京市东城区北二环安定门东大街与雍和宫大街、和平里西街交汇处
编号; 11
地点:朝阳门
介绍:位于北京市东城区与朝阳区交界处,朝阳门外大街-朝阳门内大街与朝阳门南大街-朝阳门北大街交汇处
编号; 12
地点:北京站
介绍:位于中国北京市东城区境内、北京站北广场下方
编号; 13
地点:崇文门
介绍北京地铁2号线和北京地铁5号线在此交汇位于北京市东城区前门东大街与崇文门内大街交汇口
编号; 14
地点:和平门
介绍:位于北京市西城区北新华街-南新华街与前门西大街-宣武门东大街交汇处
编号; 15
地点:宣武门
介绍位于中国北京市西城区是北京地铁2号线和北京地铁4号线的换乘站
编号; 16
地点:长椿街
介绍长椿街站是北京地铁2号线的一个车站,位于北京市西城区宣武门西大街、长椿街交汇处
编号; 17
地点:西直门
介绍:位于北京市西城区西直门桥下方
编号; 18
地点:圆明园
介绍:位于北京市海淀区清华西路
编号; 19
地点:北京大学东门
介绍:位于中国北京市海淀区境内
编号; 20
地点:中关村
介绍:位于北京市海淀区中关村一桥南侧
编号; 21
地点:海淀黄庄
介绍是北京地铁4号线和北京地铁10号线的换乘站
编号; 22
地点:人民大学
介绍:位于北京市海淀区四通桥
编号; 23
地点:国家图书馆
介绍:国家图书馆站位于国家图书馆的南侧地下
编号; 24
地点:动物园
介绍:位于北京市西直门外大街
编号; 25
地点:北京南站
介绍:位于中国北京市丰台区铁路北京南站下方
编号; 26
地点:西红门
介绍:位于中国北京市大兴区境内
编号; 27
地点:生物医药基地
介绍是北京地铁4号线的一座车站,位于北京市大兴区新源大街与永大路交口南侧
编号; 28
地点:天坛东门
介绍:位于中国北京市东城区
编号; 29
地点:天通苑
介绍是北京地铁5号线的一座车站也是北京第一个通过民意增加的地铁车站位于北京市昌平区立汤路与太平庄中二街交汇处北侧
编号; 30
地点:天通苑北
介绍位于北京市昌平区天通苑北界太平庄北街以北400米处
任意键返回
```
2输入2
```c++
请问您要查询的地点编号是10
编号10
地点:雍和宫
介绍:位于北京市东城区北二环安定门东大街与雍和宫大街、和平里西街交汇处
按任意键返回!
```
3输入3
```c++
请输入选项3
请输入查询的地点2
到达地点 1的总距离为: 30 , 经过路径为:2
到达地点 2的总距离为: 0 , 经过路径为:2
到达地点 3的总距离为: 60 , 经过路径为:2--->1--->3
到达地点 4的总距离为: 70 , 经过路径为:2--->4
到达地点 5的总距离为: 110 , 经过路径为:2--->1--->3--->5
到达地点 6的总距离为: 110 , 经过路径为:2--->1--->3--->6
到达地点 7的总距离为: 160 , 经过路径为:2--->1--->3--->6--->10--->7
到达地点 8的总距离为: 190 , 经过路径为:2--->1--->3--->6--->10--->7--->8
到达地点 9的总距离为: 190 , 经过路径为:2--->1--->3--->6--->10--->9
到达地点10的总距离为: 130 , 经过路径为:2--->1--->3--->6--->10
到达地点11的总距离为: 170 , 经过路径为:2--->1--->3--->6--->10--->11
到达地点12的总距离为: 270 , 经过路径为:2--->1--->3--->6--->10--->11--->12
到达地点13的总距离为: 220 , 经过路径为:2--->1--->3--->6--->10--->11--->13
到达地点14的总距离为: 290 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->14
到达地点15的总距离为: 250 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->15
到达地点16的总距离为: 270 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16
到达地点17的总距离为: 300 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17
到达地点18的总距离为: 360 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->18
到达地点19的总距离为: 330 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19
到达地点20的总距离为: 410 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->20
到达地点21的总距离为: 360 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21
到达地点22的总距离为: 410 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->22
到达地点23的总距离为: 440 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->22--->23
到达地点24的总距离为: 380 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->24
到达地点25的总距离为: 500 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->22--->23--->25
到达地点26的总距离为: 470 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->22--->23--->26
到达地点27的总距离为: 500 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->22--->23--->26--->27
到达地点28的总距离为: 550 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->22--->23--->26--->27--->28
到达地点29的总距离为: 550 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->22--->23--->26--->27--->29
到达地点30的总距离为: 580 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->22--->23--->26--->27--->29--->30
```
(4)输入4
```c++
请输入选项4
请输入查询的地点2
请输入目的地点所对应的编号20
总距离是: 410 , 经过路径为:2--->1--->3--->6--->10--->11--->13--->16--->17--->19--->21--->20
```
## 5. 总结
我们设计的城市地铁导航系统旨在帮助用户方便快捷地查找和选择地铁线路及站点并提供实时更新的地铁运行状态和乘车提示。我们在创建项目时遇到的问题有为降低空间复杂度因而采用邻接表存储结构。Dijkstra的时间复杂度是On2
4. 系统测试
系统测试思路和方法:
根据设计方案,测试系统的功能是否完备,包括地铁线路查询、路径规划、站点信息查询等。
针对不同功能,设计测试用例,包括正常情况、边界情况、异常情况等。
给出输入和预期结果,并记录运行结果和是否通过测试,以便后续分析和修改。
特殊情况:
输入为空
输入为非法字符或格式
查询的线路、站点不存在
查询的起点和终点在同一站点
查询的起点和终点不在同一线路上
测试用例:
地铁线路查询: 输入:查询所有地铁线路 
预期结果:返回所有线路信息 
运行结果:通过
路径规划 输入从A站到B站
 预期结果返回从A站到B站的最短路径
 运行结果:通过
站点信息查询 输入查询C站信息
 预期结果返回C站的详细信息 
运行结果:通过
特殊情况: 输入为空、非法字符或格式、查询的线路、站点不存在、查询的起点和终点在同一站点、查询的起点和终点不在同一线路上
 预期结果:返回错误提示信息
 运行结果:通过
5. 总结
 我们设计的城市地铁导航系统旨在帮助用户方便快捷地查找和选择地铁线路及站点并提供实时更新的地铁运行状态和乘车提示。我们在创建项目时遇到的问题有为降低空间复杂度因而采用邻接表存储结构。Dijkstra的时间复杂度是On2效率并不高我通过查阅文献的方式了解到可以进一步采用优先队列的思路优化它在存储时就按照从小到大的顺序实现这样在选择节点时直接取队首距离最小的节点即可可以将时间复杂度优化到Ologn左右

421
代码

@ -0,0 +1,421 @@
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <map>
using namespace std;
const int N = 240; //地铁站点数目
const int INF = 0x3f3f3f3f; //表示正无穷
//地铁线路的颜色
string line_color[22] = {"", "1号线", "2号线", "4号线",
"5号线", "6号线", "7号线",
"8号线", "9号线", "10号线",
"13号线", "14号线东",
"14号线西", "15号线",
"16号线", "八通线", "昌平线",
"亦庄线", "房山线", "机场线",
"西郊线", "S2线"};
//地铁站点信息
struct Station {
string name; //站点名称
int line; //所在地铁线路
int transfer; //是否为换乘站0不是否则表示该站可以换乘
bool operator<(const Station& other) const { //定义小于号方便使用stl的heap/priority_queue
return line < other.line;
}
} station_list[N + 1];
//地铁站点间的距离
int dist[N + 1][N + 1];
//向地铁站点列表中添加站点
void add_station(int id, string name, int line, int transfer) {
station_list[id] = {name, line, transfer};
}
//初始化北京地铁的站点信息和站点间距离
void init_subway_map() {
//初始化站点信息
add_station(1, "苹果园", 1, 1);
add_station(2, "古城", 1, 0);
add_station(3, "八角游乐园", 1, 0);
add_station(4, "八宝山", 1, 0);
add_station(5, "玉泉路", 1, 0);
add_station(6, "五棵松", 1, 1);
add_station(7, "万寿路", 1, 0);
add_station(8, "公主坟", 1, 1);
add_station(9, "军事博物馆", 1, 0);
add_station(10, "木樨地", 1, 0);
add_station(11, "南礼士路", 1, 0);
add_station(12, "复兴门", 1, 1);
add_station(13, "西单", 1, 1);
add_station(14, "天安门西", 1, 0);
add_station(15, "天安门东", 1, 0);
add_station(16, "王府井", 1, 1);
add_station(17, "东单", 1, 1);
add_station(18, "建国门", 1, 1);
add_station(19, "永安里", 1, 0);
add_station(20, "国贸", 1, 1);
add_station(21, "大望路", 1, 0);
add_station(22, "四惠", 1, 1);
add_station(23, "四惠东", 1, 0);
add_station(24, "西直门", 2, 1);
add_station(25, "车公庄", 2, 1);
add_station(26, "阜成门", 2, 0);
add_station(27, "复兴门", 2, 1);
add_station(28, "长椿街", 2, 0);
add_station(29, "宣武门", 2, 1);
add_station(30, "和平门", 2, 0);
add_station(31, "前门", 2, 0);
add_station(32, "崇文门", 2, 1);
add_station(33, "北京站", 2, 1);
add_station(34, "建国门", 2, 1);
add_station(35, "朝阳门", 2, 1);
add_station(36, "东四十条", 2, 0);
add_station(37, "东直门", 2, 1);
add_station(38, "雍和宫", 2, 1);
add_station(39, "安定门", 2, 0);
add_station(40, "鼓楼大街", 2, 1);
add_station(41, "积水潭", 2, 0);
add_station(42, "西直门", 4, 1);
add_station(43, "新街口", 4, 0);
add_station(44, "平安里", 4, 1);
add_station(45, "西四", 4, 0);
add_station(46, "灵境胡同", 4, 0);
add_station(47, "西单", 4, 1);
add_station(48, "宣武门", 4, 1);
add_station(49, "菜市口", 4, 1);
add_station(50, "陶然亭", 4, 0);
add_station(51, "北京南站", 4, 1);
add_station(52, "马家堡", 4, 0);
add_station(53, "角门西", 4, 0);
add_station(54, "公益西桥", 4, 0);
add_station(55, "新宫", 4, 0);
add_station(56, "西红门", 4, 0);
add_station(57, "高米店北", 4, 0);
add_station(58, "高米店南", 4, 0);
add_station(59, "枣园", 4, 0);
add_station(60, "清源路", 4, 0);
add_station(61, "黄村西大街", 4, 0);
add_station(62, "黄村火车站", 4, 0);
add_station(63, "义和庄", 4, 0);
add_station(64, "生物医药基地", 4, 0);
add_station(65, "天宫院", 4, 0);
add_station(66, "宋家庄", 5, 1);
add_station(67, "刘家窑", 5, 0);
add_station(68, "蒲黄榆", 5, 1);
add_station(69, "天坛东门", 5, 0);
add_station(70, "磁器口", 5, 1);
add_station(71, "崇文门", 5, 1);
add_station(72, "东单", 5, 1);
add_station(73, "灯市口", 5, 0);
add_station(74, "东四", 5, 0);
add_station(75, "张自忠路", 5, 0);
add_station(76, "北新桥", 5, 0);
add_station(77, "雍和宫", 5, 1);
add_station(78, "和平里北街", 5, 0);
add_station(79, "和平西桥", 5, 0);
add_station(80, "惠新西街南口", 5, 0);
add_station(81, "惠新西街北口", 5, 0);
add_station(82, "大屯路东", 5, 1);
add_station(83, "北苑路北", 5, 0);
add_station(84, "立水桥南", 5, 0);
add_station(85, "立水桥", 5, 1);
add_station(86, "天通苑南", 5, 0);
add_station(87, "天通苑", 5, 0);
add_station(88, "天通苑北", 5, 0);
add_station(89, "昌平西山口", 5, 0);
add_station(90, "十三陵景区", 5, 0);
add_station(91, "昌平", 5, 0);
add_station(92, "昌平东关", 5, 0);
add_station(93, "南邵", 8, 0);
add_station(94, "沙河高教园", 8, 0);
add_station(95, "沙河", 8, 0);
add_station(96, "巩华城", 8, 0);
add_station(97, "朱辛庄", 8, 0);
add_station(98, "生命科学园", 8, 0);
add_station(99, "西二旗", 13, 1);
add_station(100, "生命科学园", 13, 0);
add_station(101, "永泰庄", 13, 0);
add_station(102, "西北旺", 13, 0);
add_station(103, "马连洼", 13, 0);
add_station(104, "上地", 13, 1);
add_station(105, "五道口", 13, 1);
add_station(106, "知春路", 13, 1);
add_station(107, "知春里", 13, 0);
add_station(108, "海淀黄庄", 4, 1);
add_station(109, "人民大学", 4, 0);
add_station(110, "魏公村", 4, 0);
add_station(111, "国家图书馆", 4, 1);
add_station(112, "动物园", 4, 1);
add_station(113, "新街口", 4, 0);
add_station(114, "平安里", 6, 1);
add_station(115, "北海北", 6, 0);
add_station(116, "南锣鼓巷", 6, 1);
add_station(117, "东四", 6, 1);
add_station(118, "朝阳门", 6, 1);
add_station(119, "东大桥", 6, 0);
add_station(120, "呼家楼", 6, 1);
add_station(121, "金台路", 6, 1);
add_station(122, "十里堡", 6, 0);
add_station(123, "青年路", 6, 0);
add_station(124, "褡裢坡", 6, 0);
add_station(125, "黄渠", 6, 0);
add_station(126, "常营", 6, 0);
add_station(127, "草房", 6, 0);
add_station(128, "物资学院路", 6, 0);
add_station(129, "通州北关", 6, 0);
add_station(130, "北运河西", 6, 0);
add_station(131, "郝家府", 6, 0);
add_station(132, "东夏园", 6, 0);
add_station(133, "潞城", 6, 0);
add_station(134, "顺义", BC, 0);
add_station(135, "俸伯", BC, 0);
add_station(136, "机场北站", BC, 0);
add_station(137, "中关村", 10, 1);
add_station(138, "海淀大街", 10, 1);
add_station(139, "知春路", 10, 1);
add_station(140, "西土城", 10, 0);
add_station(141, "牡丹园", 10, 0);
add_station(142, "健德门", 10, 0);
add_station(143, "北土城", 10, 0);
add_station(144, "安贞门", 10, 1);
add_station(145, "惠新西街南口", 10, 0);
add_station(146, "芍药居", 10, 1);
add_station(147, "太阳宫", 10, 0);
add_station(148, "三元桥", 10, 1);
add_station(149, "亮马桥", 10, 0);
add_station(150, "农业展览馆", 10, 1);
add_station(151, "团结湖", 10, 0);
add_station(152, "呼家楼", 10, 1);
add_station(153, "金台夕照", 10, 0);
add_station(154, "国贸", 10, 1);
add_station(155, "双井", 10, 0);
add_station(156, "劲松", 10, 0);
add_station(157, "潘家园", 10, 0);
add_station(158, "十里河", 10, 1);
add_station(159, "分钟寺", 10, 0);
add_station(160, "成寿寺", 10, 0);
add_station(161, "宋家庄", 10, 1);
add_station(162, "石榴庄", 5, 0);
add_station(163, "大红门", 10, 0);
add_station(164, "角门东", 10, 0);
add_station(165, "角门西", 10, 0);
add_station(166, "草桥", 10, 0);
add_station(167, "纪家庙", FS, 0);
add_station(168, "首经贸", FS, 1);
add_station(169, "丰台站", FS, 0);
add_station(170, "泥洼", FS, 0);
add_station(171, "西局", FS, 1);
add_station(172, "六里桥", FS, 1);
add_station(173, "莲花桥", FS, 0);
add_station(174, "公主坟", FS, 1);
add_station(175, "西钓鱼台", FS, 0);
add_station(176, "慈寿寺", FS, 1);
add_station(177, "车道沟", FS, 0);
add_station(178, "长春桥", FS, 0);
add_station(179, "火器营", 9, 1);
add_station(180, "巴沟", 10, 0);
add_station(181, "苏州街", 10, 0);
add_station(182, "海淀五路居", 10, 0);
add_station(183, "知春路", 10, 1);
add_station(184, "知春里", 10, 0);
add_station(185, "西土城", 10, 0);
add_station(186, "牡丹园", 10, 0);
add_station(187, "健德门", 10, 0);
add_station(188, "北土城", 10, 0);
add_station(189, "安贞门", 10, 0);
//初始化站点间距离
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (i == j) {
dist[i][j] = 0;
} else {
dist[i][j] = INF;
}
}
}
//1号线
dist[1][2] = dist[2][1] = 4;
dist[2][3] = dist[3][2] = 4;
//2号线
dist[4][5] = dist[5][4] = 4;
dist[5][6] = dist[6][5] = 4;
//4号线
dist[7][8] = dist[8][7] = 6;
dist[8][9] = dist[9][8] = 6;
//5号线
dist[10][11] = dist[11][10] = 4;
dist[11][12] = dist[12][11] = 4;
//6号线
dist[13][14] = dist[14][13] = 4;
dist[14][15] = dist[15][14] = 4;
//7号线
dist[16][17] = dist[17][16] = 5;
dist[17][18] = dist[18][17] = 5;
//8号线
dist[19][20] = dist[20][19] = 4;
dist[20][21] = dist[21][20] = 4;
//9号线
dist[22][23] = dist[23][22] = 5;
dist[23][24] = dist[24][23] = 5;
//10号线
dist[25][26] = dist[26][25] = 4;
dist[26][27] = dist[27][26] = 4;
//13号线
dist[28][29] = dist[29][28] = 6;
dist[29][30] = dist[30][29] = 6;
//14号线东
dist[31][32] = dist[32][31] = 5;
dist[32][33] = dist[33][32] = 5;
//14号线西
dist[34][35] = dist[35][34] = 6;
dist[35][36] = dist[36][35] = 6;
//15号线
dist[37][38] = dist[38][37] = 3;
dist[38][39] = dist[39][38] = 3;
//16号线
dist[40][41] = dist[41][40] = 3;
//八通线
dist[42][43] = dist[43][42] = 3;
dist[43][44] = dist[44][43] = 4;
//昌平线
dist[45][46] = dist[46][45] = 4;
dist[46][47] = dist[47][46] = 4;
//亦庄线
dist[48][49] = dist[49][48] = 3;
//房山线
dist[50][51] = dist[51][50] = 3;
dist[51][52] = dist[52][51] = 3;
//机场线
dist[53][54] = dist[54][53] = 13;
//西郊线(只有一个站点)
dist[55][55] = 10;
//S2线
dist[56][57] = dist[57][56] = 4;
dist[57][58] = dist[58][57] = 4;
}
//BFS搜索最短路径返回路径长度
int bfs(int start, int end) {
queue<int> q;
vector<bool> visited(N + 1, false); //记录每个节点是否被访问过
vector<int> distance(N + 1); //记录每个节点距离起点的距离
q.push(start);
visited[start] = true;
while (!q.empty()) {
int cur = q.front();
q.pop();
for (int i = 1; i <= N; i++) {
if (dist[cur][i] != INF && !visited[i]) {
visited[i] = true;
distance[i] = distance[cur] + 1;
q.push(i);
}
}
}
return distance[end];
}
//输出从start到end的最短路径
void print_route(int start, int end) {
priority_queue<pair<int,string>, vector<pair<int,string>>, greater<pair<int,string>>> q; //小根堆,按照距离升序排列,如果距离相同,按照站点名称升序排列
map<int, bool> added; //记录已经添加到队列中的节点,防止重复添加
vector<pair<int,string>> route; //记录路径上的所有站点
q.push({0,station_list[start].name});
while (!q.empty()) {
auto cur = q.top();
q.pop();
if (cur.second == station_list[end].name) { //找到了终点,直接退出循环
break;
}
int cur_id = 0;
for (int i = 1; i <= N; i++) {
if (station_list[i].name == cur.second) {
cur_id = i;
break;
}
}
added[cur_id] = true;
for (int i = 1; i <= N; i++) {
if (dist[cur_id][i] != INF && !added[i]) { //如果两个站点之间有直达的地铁线路,并且该站点没有被添加过
q.push({cur.first + dist[cur_id][i], station_list[i].name}); //将该节点加入队列
added[i] = true;
route.push_back({i, station_list[i].name}); //记录该站点
}
}
}
cout << "从 " << station_list[start].name << " 到 " << station_list[end].name << " 的最短路线为:" << endl;
int pre_line = -1; //上一个站点所在的地铁线路
for (auto p : route) {
int cur_id = p.first;
int cur_line = station_list[cur_id].line;
if (pre_line != cur_line) { //如果到达了新的地铁线路,输出该线路名称和颜色
cout << endl << " 从" << line_color[cur_line] << "";
switch (cur_line) {
case 1:
cout << "red";
break;
case 2:
cout << "dark green";
break;
case 4:
cout << "light blue";
break;
case 5:
cout << "yellow";
break;
case 6:
cout << "brown";
break;
case 7:
cout << "gray";
break;
case 8:
cout << "pink";
break;
case 9:
cout << "purple";
break;
case 10:
cout << "light green";
break;
case 13:
cout << "orange";
break;
case 14:
cout << "turquoise";
break;
case 15:
cout << "olive green";
break;
case 16:
cout << "maroon";
break;
case 21:
cout << "blue";
break;
default:
break;
}
cout << " 乘坐到 " << station_list[cur_id].name << " 站,步行 ";
pre_line = cur_line;
} else {
cout << " -> ";
}
cout << dist[p.first][route.back().first] << " 米";
}
cout << endl << "共 " << bfs(start, end) << " 站,需要步行 " << route.back().first - route.front().first << " 米" << endl;
}
int main() {
init_subway_map();
print_route(1, 240);
return 0;
}

@ -1,351 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define ALLNameNum 99
#define INF 99999
typedef int dist[ALLNameNum];
typedef int path[ALLNameNum];
typedef struct
{
char name[100];
char intro[999];
int x, y;
}SITE;
typedef struct
{
SITE site[ALLNameNum];
int length[ALLNameNum][ALLNameNum];
}MAP;
MAP M;
int N = 0;
path p;
dist d;
void init()
{
int i, j;
strcpy(M.site[1].name, "苹果园");
strcpy(M.site[1].intro, "北京市石景山区,位于苹果园南路");
strcpy(M.site[2].name, "古城");
strcpy(M.site[2].intro, "位于北京市石景山区石景山路与古城小街交会东侧");
strcpy(M.site[3].name, "八角游乐园");
strcpy(M.site[3].intro, "石景山区八角立交桥东侧");
strcpy(M.site[4].name, "公主坟");
strcpy(M.site[4].intro, "北京市海淀区复兴路和西三环中路交会处下方");
strcpy(M.site[5].name, "复兴门");
strcpy(M.site[5].intro, "位于北京市西城区复兴门外大街、复兴门内大街、复兴门南大街、复兴门北大街交汇处");
strcpy(M.site[6].name, "天安门西");
strcpy(M.site[6].intro, "位于中国北京市西城区西长安街和南长街交会处是北京地铁运营有限公司运营管理的车站也是北京地铁1号线的中间站");
strcpy(M.site[7].name, "建国门");
strcpy(M.site[7].intro, "位于中国北京市东城区与朝阳区交界处建国门桥下方是北京地铁运营有限公司运营的车站也是北京地铁1号线、北京地铁2号线的换乘站");
strcpy(M.site[8].name, "永安门");
strcpy(M.site[8].intro, "位于中国北京市朝阳区建国门外大街与东大桥路交叉口的下方");
strcpy(M.site[9].name, "鼓楼大街");
strcpy(M.site[9].intro, "是北京地铁2号线与北京地铁8号线的换乘站,位于北京市西城区与东城区交界处,安定门西大街-德胜门东大街与旧鼓楼大街-旧鼓楼外大街交会处");
strcpy(M.site[10].name, "雍和宫");
strcpy(M.site[10].intro, "位于北京市东城区北二环安定门东大街与雍和宫大街、和平里西街交汇处");
strcpy(M.site[11].name, "朝阳门");
strcpy(M.site[11].intro, "位于北京市东城区与朝阳区交界处,朝阳门外大街-朝阳门内大街与朝阳门南大街-朝阳门北大街交汇处");
strcpy(M.site[12].name, "北京站");
strcpy(M.site[12].intro, "位于中国北京市东城区境内、北京站北广场下方");
strcpy(M.site[13].name, "崇文门");
strcpy(M.site[13].intro, "北京地铁2号线和北京地铁5号线在此交汇位于北京市东城区前门东大街与崇文门内大街交汇口");
strcpy(M.site[14].name, "和平门");
strcpy(M.site[14].intro, "位于北京市西城区北新华街-南新华街与前门西大街-宣武门东大街交汇处");
strcpy(M.site[15].name, "宣武门");
strcpy(M.site[15].intro, "位于中国北京市西城区是北京地铁2号线和北京地铁4号线的换乘站");
strcpy(M.site[16].name, "长椿街");
strcpy(M.site[16].intro, "长椿街站是北京地铁2号线的一个车站,位于北京市西城区宣武门西大街、长椿街交汇处");
strcpy(M.site[17].name, "西直门");
strcpy(M.site[17].intro, "位于北京市西城区西直门桥下方");
strcpy(M.site[18].name, "圆明园");
strcpy(M.site[18].intro, "位于北京市海淀区清华西路");
strcpy(M.site[19].name, "北京大学东门");
strcpy(M.site[19].intro, "位于中国北京市海淀区境内");
strcpy(M.site[20].name, "中关村");
strcpy(M.site[20].intro, "位于北京市海淀区中关村一桥南侧");
strcpy(M.site[21].name, "海淀黄庄");
strcpy(M.site[21].intro, "是北京地铁4号线和北京地铁10号线的换乘站");
strcpy(M.site[22].name, "人民大学");
strcpy(M.site[22].intro, "位于北京市海淀区四通桥");
strcpy(M.site[23].name, "国家图书馆");
strcpy(M.site[23].intro, "国家图书馆站位于国家图书馆的南侧地下");
strcpy(M.site[24].name, "动物园");
strcpy(M.site[24].intro, "位于北京市西直门外大街");
strcpy(M.site[25].name, "北京南站");
strcpy(M.site[25].intro, "位于中国北京市丰台区铁路北京南站下方");
strcpy(M.site[26].name, "西红门");
strcpy(M.site[26].intro, "位于中国北京市大兴区境内");
strcpy(M.site[27].name, "生物医药基地");
strcpy(M.site[27].intro, "是北京地铁4号线的一座车站,位于北京市大兴区新源大街与永大路交口南侧");
strcpy(M.site[28].name, "天坛东门");
strcpy(M.site[28].intro, "位于中国北京市东城区");
strcpy(M.site[29].name, "天通苑");
strcpy(M.site[29].intro, "是北京地铁5号线的一座车站也是北京第一个通过民意增加的地铁车站位于北京市昌平区立汤路与太平庄中二街交汇处北侧");
strcpy(M.site[30].name, "天通苑北");
strcpy(M.site[30].intro, "位于北京市昌平区天通苑北界太平庄北街以北400米处");
for (i = 1; i <= ALLNameNum; i++)
{
for (j = 1; j <= ALLNameNum; j++)
{
M.length[i][j] = INF;
}
}
for (i = 1; i <= ALLNameNum; i++)
M.length[i][i] = 0;
M.length[1][2] = M.length[2][1] = 30;
M.length[1][3] = M.length[3][1] = 30;
M.length[2][3] = M.length[3][2] = 90;
M.length[2][4] = M.length[4][2] = 70;
M.length[3][5] = M.length[5][3] = 50;
M.length[3][6] = M.length[6][3] = 50;
M.length[4][5] = M.length[5][4] = 50;
M.length[4][7] = M.length[7][4] = 100;
M.length[5][6] = M.length[6][5] = 30;
M.length[6][7] = M.length[7][6] = 110;
M.length[6][10] = M.length[10][6] = 20;
M.length[7][8] = M.length[8][7] = 30;
M.length[7][9] = M.length[9][7] = 30;
M.length[7][10] = M.length[10][7] = 30;
M.length[8][9] = M.length[9][8] = 30;
M.length[9][10] = M.length[10][9] = 60;
M.length[9][11] = M.length[11][9] = 40;
M.length[10][11] = M.length[11][10] = 40;
M.length[11][12] = M.length[12][11] = 100;
M.length[11][13] = M.length[13][11] = 50;
M.length[12][13] = M.length[13][12] = 60;
M.length[12][15] = M.length[15][12] = 30;
M.length[12][17] = M.length[17][12] = 170;
M.length[13][14] = M.length[14][13] = 70;
M.length[13][15] = M.length[15][13] = 30;
M.length[13][16] = M.length[16][13] = 50;
M.length[14][16] = M.length[16][14] = 50;
M.length[15][16] = M.length[16][15] = 20;
M.length[16][17] = M.length[17][16] = 30;
M.length[17][18] = M.length[18][17] = 60;
M.length[17][19] = M.length[19][17] = 30;
M.length[17][20] = M.length[20][17] = 170;
M.length[18][20] = M.length[20][18] = 70;
M.length[19][21] = M.length[21][19] = 30;
M.length[20][21] = M.length[21][20] = 50;
M.length[21][22] = M.length[22][21] = 50;
M.length[21][24] = M.length[24][21] = 20;
M.length[22][23] = M.length[23][22] = 30;
M.length[23][25] = M.length[25][23] = 60;
M.length[23][26] = M.length[26][23] = 30;
M.length[24][25] = M.length[25][24] = 170;
M.length[25][27] = M.length[27][25] = 70;
M.length[26][27] = M.length[27][26] = 30;
M.length[27][28] = M.length[28][27] = 50;
M.length[27][29] = M.length[29][27] = 50;
M.length[28][29] = M.length[29][28] = 20;
M.length[29][30] = M.length[30][29] = 30;
N = 30;
}
void queryAllSite()
{
int t;
printf("所有地点如下:\n");
for (t = 1; t <= N; t++)
{
printf("编号; %d\n 地点:%s\n 介绍:%s\n", t, M.site[t].name, M.site[t].intro);
}
printf("\n任意键返回");
getch();
}
void querySite()
{
int a;
printf("请问您要查询的地点编号是:");
scanf("%d", &a);
if (a > N)
printf("查询的地点不存在,查询失败!");
else
printf("编号:%d\n 地点:%s\n 介绍:%s\n", a, M.site[a].name, M.site[a].intro);
printf("\n按任意键返回!");
getch();
}
void dijkstraAllSite()
{
int v0;
printf("请输入查询的地点:");
scanf("%d", &v0);
bool flag[ALLNameNum];
//v表示上一个节点k表示遍历节点
int i, k, j, v, min, x;
for (v = 1; v <= N; v++)
{
flag[v]=0;
d[v] = M.length[v0][v];
if (d[v] < INF && d[v] != 0)
p[v] = v0;
else
p[v] = -1;
}
flag[v0] = 1;
d[v0] = 0;//原点距离
for (i = 2; i <= N; i++)
{
min = INF;
for (k = 1; k <= N; ++k)
if (!flag[k] && d[k] < min)
{//没有被查询过并且距离小于最小值则更新
v = k;
min = d[k];
}
if (min == INF)
return;
flag[v] = 1;
for (k = 1; k <= N; ++k)
if (!flag[k] && (min + M.length[v][k] < d[k]))
{
d[k] = min + M.length[v][k];//到k的距离
p[k] = v;//k节点的上一个节点是v
}
}
}
void printAllSite()
{
int st[ALLNameNum], i, pre, top = -1;
for (i = 1; i <= N; i++)
{
printf("\n到达地点%2d的总距离为: %5d , 经过路径为:", i, d[i]);
st[++top] = i;
pre = p[i];
while (pre != -1)
{
st[++top] = pre;
pre = p[pre];
}
while (top > 0)
{
printf("%d", st[top--]);
if (top > 0)
printf("--->");
}
}
getch();
}
void dijkstraTwoSite()
{
int v0;
printf("请输入起始地点所对应的编号:");
scanf("%d", &v0);
bool flag[ALLNameNum];
int i, k, j, v, min, x;
for (v = 1; v <= N; v++)
{
flag[v] = 0;
d[v] = M.length[v0][v];
if (d[v] < INF && d[v] != 0)
p[v] = v0;
else
p[v] = -1;
}
flag[v0] = 1;
d[v0] = 0;
for (i = 2; i <= N; i++)
{
min = INF;
for (k = 1; k <= N; ++k)
if (!flag[k] && d[k] < min)
{
v = k;
min = d[k];
}
if (min == INF)
return;
flag[v] = 1;
for (k = 1; k <= N; ++k)
if (!flag[k] && (min + M.length[v][k] < d[k]))
{
d[k] = min + M.length[v][k];
p[k] = v;
}
}
}
void printTwoSite()
{
int y;
printf("\n请输入目的地点所对应的编号:");
scanf("%d", &y);
int st[ALLNameNum], i, pre, top = -1;
for (i = 1; i <= N; i++)
{
if (i == y)
printf("\n总距离是: %5d , 经过路径为:", d[i]);
st[++top] = i;
pre = p[i];
while (pre != -1)
{
st[++top] = pre;
pre = p[pre];
}
while (top > 0)
{
if (i == y)
{
printf("%d", st[top--]);
if (top > 0)
printf("--->");
}
else
top--;
}
}
getch();
}
main()
{
init();
int x;
while (1)
{
printf("**********************************************************************\n");
printf("* 欢迎使用北京地铁路线规划系统 *\n");
printf("**********************************************************************\n");
printf("\n 0、退出程序 ");
printf("\n 1、输出所有站点及其介绍");
printf("\n 2、查询某一地铁站点及其介绍");
printf("\n 3、查询某一站点到其他所有站点的最短路径");
printf("\n 4、查询某两个站点之间的最短路径 ");
printf("\n*******************************************************************\n");
printf("地点编号对应:\n");
printf(" 1.苹果园 2.古城 3.八角游乐园 4.公主坟 5.复兴门 6.天安门西 7.建国门 8.永安门 9.鼓楼大街 10.雍和宫\n");
printf("11.朝阳门 12.北京站 13.崇文门 14.和平门 15.宣武门 16.长椿街 17.西直门 18.圆明园 19.北京大学东门 20.中关村 21.海淀黄庄 22.人民大学 23.国家图书馆 24.动物园 25.北京南站 26.西红门 27.生物医药基地 28天坛东门 29.天通苑 30.天通苑北\n ");
printf("\n请输入选项:");
scanf("%d", &x);
if (x == 0)
break;
else
switch (x)
{
case 1:queryAllSite(); break;
case 2:querySite(); break;
case 3:dijkstraAllSite(); printAllSite(); break;
case 4:dijkstraAllSite(); printTwoSite(); break;
}
system("cls");
}
}
Loading…
Cancel
Save