数据结构第七次作业·第四题·北京地铁线路查询Dijkstra算法
一.Dikjstra算法:
(部分内容出自博客Dijkstra算法(迪杰斯特拉算法)_持之以恒2016-CSDN博客)
基本思想:
Dikjstra算法采用广度优先策略,从起始点v0开始,层层向外拓展。正是如此,导致其搜索成功率较高但是时间复杂度较大为O(n²)。
将顶点划分为两种:集合S:已经确定最短路径的顶点;集合U:没有确定最短路径的顶点。
操作步骤
1.初始:从s开始,S中只有元素S,其他元素都在U中。且U中顶点与s的距离定义为:若U,s直接连接,则其距离就为其邻接矩阵定义的距离。若U,s不直接连接,则其距离为无穷大(INF)。这样定义是因为可以优先考虑与D相邻的顶点,实现BFS。
2.从U中选出距离最小的顶点k,并把k加入到S中。且k的前序就是v0。
3.更新距离:以k为依托,与k直接连接的顶点到v0的距离(但不一定最小)就等于其到k的距离加上k到v0的距离。若这个距离小于当前记录的距离,则这个顶点的前序就是k。
4.重复2,3到遍历结束。
图解示例
----- S是已计算出最短路径的顶点的集合
----- U是未计算出最短路径的顶点的集合
----- C(3)表示顶点C到起点D的最短距离为3
选择顶点D
S={D(0)}
U={A(∞), B(∞), C(3), E(4), F(∞), G(∞)}
选取顶点C
S={D(0), C(3)}
U={A(∞), B(13), E(4), F(9), G(∞)}
选取顶点E
S={D(0), C(3), E(4)}
U={A(∞), B(13), F(6), G(12)}
选取顶点F
S={D(0), C(3), E(4), F(6)}
U={A(22), B(13), G(12)}
选取顶点G
S={D(0), C(3), E(4), F(6), G(12)}
U={A(22), B(13)}
选取顶点B
S={D(0), C(3), E(4), F(6), G(12), B(13)}
U={A(22)}
选取顶点A
S={D(0), C(3), E(4), F(6), G(12), B(13), A(22)}
U={}
代码如下:
void Dijkstra(int v0){int minweight,minv;int wfound[MAXVEX]={0};//to sign if the shortest path from i to v0 is foundfor(int i=0;i<vnum;i++){sweight[i]=mat[v0][i].weight;spath[i]=v0;wfound[i]=0;}sweight[v0]=0;wfound[v0]=1;for(int i=0;i<vnum-1;i++){minweight =INF;for(int j=0;j<vnum;j++){if(!wfound[j]&&sweight[j]<minweight){minv = j;minweight = sweight[minv];}}wfound[minv]=1;for(int j=0;j<vnum;j++){if(!wfound[j]&&(minweight + mat[minv][j].weight)<sweight[j]){sweight[j]=minweight+mat[minv][j].weight;spath[j]=minv;}}}
}
二.北京地铁
题面如下:
编写一个程序实现北京地铁最短乘坐(站)线路查询,输入为起始站名和目的站名,输出为从起始站到目的站的最短乘坐站换乘线路。注:1. 要求采用Dijkstra算法实现;2)如果两站间存在多条最短路径,找出其中的一条就行。
【输入形式】
文件bgstations.txt为数据文件(可从课程网站中课程信息处下载),包含了北京地铁的线路及车站信息。其格式如下:
<地铁线路总条数>
<线路1> <线路1站数>
<站名1> <换乘状态>
<站名2> <换乘状态>
...
<线路2> <线路2站数>
<站名1> <换乘状态>
<站名2> <换乘状态>
...
说明:文件第一行为地铁总线路数;第二行第一个数为某条地铁线线号(如,1为1号线),第二个数为该条地铁线的总站数(如1号线共有23站),两数之间由一个空格分隔;第三行两个数据分别为地铁站名及换乘状态(0为非换乘站,1为换乘站),两数据间由一个空格分隔;以下同,依次为该线地铁其它站信息。在一条线路信息之后是下条地铁线路信息,格式相同。若某条地铁线为环线,则首站与末站信息相同(如北京地铁2号线,首站信息“西直门 1” ,末站信息为“西直门 1”)。例如本题提供的bgstations.txt文件(可从课程网站中课程信息处下载)内容如下:
13
1 23
苹果园 0
古城 0
八角游乐园 0
八宝山 0
玉泉路 0
五棵松 0
万寿路 0
公主坟 1
军事博物馆 1
木樨地 0
南礼士路 0
复兴门 1
西单 1
...
2 19
西直门 1
积水潭 0
鼓楼大街 1
...
西直门 1
...
该文件表明当前北京地铁共有13条线路(不含郊区线路),接着为每条线路信息。
打开当前目录下文件bgstations.txt,读入地铁线路信息,并从标准输入中读入起始站和目的站名(均为字符串,各占一行)。
【输出形式】
输出从起始站到目的站的乘坐信息,要求乘坐站数最少。换乘信息格式如下:
SSN-n1(m1)-S1-n2(m2)-...-ESN
其中:SSN和ESN分别为起始站名和目的站名;n为乘坐的地铁线路号,m为乘坐站数。
【样例输入】
西土城
北京西站
【样例输出】
西土城-10(1)-知春路-13(2)-西直门-4(2)-国家图书馆-9(4)-北京西站
(或西土城-10(1)-知春路-13(2)-西直门-2(1)-车公庄-6(2)-白石桥南-9(3)-北京西站)
【样例说明】
打开文件bgstations.txt,读入地铁线路信息,并从标准输入中读入查询起始站名为“西土城”,目的站名为“北京西站”。程序运行结果两站间最少乘坐站数的乘坐方式为“西土城站乘坐10号线1站至知春路站换乘13号线乘坐2站至西直门站换乘4号线乘坐2站至国家图书馆站换乘9号线乘坐4站至北京西站”。本样例存在两条最少站数的乘坐方式,只要找出一条就可以。
【评分标准】
对于同一个起始站和目的站,如果存在多条最少站数的乘坐方式,只要找出其中一条就可以。测试点全通过得满分。
本题求解分为三个方面:建立图,用Dijkstra算法求出最短路径的前驱集合,用前驱集合输出符合要求的路径。
建立图:
注意,本题的站点是分地铁线给出的,也就是说,换乘站会出现在多条路线中。这也是建图的时候需要注意,并通过此建立线路间联系的。
由于本题没有给出边信息,所以构建边的原则就是:前一个站点和现在的站点必须要用边连接起来:这样的算法是可以解决环路的。要实现这种方法,就需要使用两个变量来存储当前和上一个结点序号。
具体操作如下:
用v1记录上一个站点,开始时v1为-1。v2记录当前输入的站点。
读入v2,若不是换乘站,就将其与直接加入到顶点集中,然后与v1(如果不是-1的话)连接起来。
若v2是换乘站,则其有可能已经被加入到了顶点集中。这时候就要去搜索其是不是在顶点集中,如果使得的话,v2就是这个顶点的下标。如果不是的话,就和上面一个加入到顶点集中。然后和上一个站连接。
代码如下:
int add_vex(Vex p){//return index(xia'biao) of p in v[];if(!p.istransfer){//if p is not a transfer stationv[vnum++]=p;return vnum-1;//add p into v and return index}else{for(int i=0;i<vnum;i++){//if p is already in v[], don't add and return its indexif(!strcmp(p.station_name,v[i].station_name))return i;}v[vnum++]=p;//if p is not in v[],add p into vreturn vnum-1;}
}void create_graph(){//to make the map of Beijing SubwayFILE *src = fopen("bgstations.txt","r");int v1,v2;//v1 is the index of last station,v2 is the index of present stationint line_cnt;Vex tmp_vex;fscanf(src,"%d",&line_cnt);for(int i=0;i<line_cnt;i++){int lineID,staion_cnt;fscanf(src,"%d%d",&lineID,&staion_cnt);v1 = v2 = -1;for(int j=0;j<staion_cnt;j++){fscanf(src,"%s%d",tmp_vex.station_name,&tmp_vex.istransfer);v2 = add_vex(tmp_vex);if(v1 !=-1){mat[v1][v2].weight=mat[v2][v1].weight =1;mat[v1][v2].line=mat[v2][v1].line =lineID;}v1 = v2;}}fclose(src);
}
用Dijkstra算法求出最短路径前驱path:
方法和代码已经给出,不再重复。
用path求路径:
注意path[i]是i的前驱,所以要求v1到v2的路径我们只能倒过来从v2开始找。找到的下标存在final_path这个数组里面。但是注意这个路径是倒过来找的,所以我们需要把这个数组在逆置一下,变成顺着的路径。
对于输出部分:
由于我们只输出换乘站(和高德差不多),所以我们需要记录当前在哪条线上面,以及在这条线上走过了多少站。到路线发生变化的时候再输出换乘站。代码如下
int tmp = index_e;while(tmp!=index_b){final_path[path_cnt++]=tmp;tmp = spath[tmp];}final_path[path_cnt++]=tmp;reverse();put_path();void reverse(){int temple[MAXVEX]={0};for(int i=0;i<path_cnt;i++){temple[path_cnt-1-i]=final_path[i];}for(int i=0;i<path_cnt;i++){final_path[i]=temple[i];}
}void put_path(){int now,last,way_now,len;last =0,now =1;way_now = mat[final_path[last]][final_path[now]].line;len = 0;printf("%s",v[final_path[0]].station_name);for(;now<path_cnt;now++){if(way_now!=mat[final_path[last]][final_path[now]].line){printf("-%d(%d)-%s",way_now,len,v[final_path[last]].station_name);way_now = mat[final_path[last]][final_path[now]].line;len = 0;}len++;last = now;}printf("-%d(%d)-%s",way_now,len,v[final_path[last]].station_name);}
最后附上完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXVEX 1000
#define INF 32767typedef struct station
{char station_name[32];int istransfer; //if the station is a transfer station
} Vex;typedef struct edge
{int weight;int line; //line of the edge
} Edge;Vex v[MAXVEX]; //vertex of station
int vnum = 0; //number of station
Edge mat[MAXVEX][MAXVEX]; //adjacency matrixint add_vex(Vex p)
{ //return index(xia'biao) of p in v[];if (!p.istransfer){ //if p is not a transfer stationv[vnum++] = p;return vnum - 1; //add p into v and return index}else{for (int i = 0; i < vnum; i++){ //if p is already in v[], don't add and return its indexif (!strcmp(p.station_name, v[i].station_name))return i;}v[vnum++] = p; //if p is not in v[],add p into vreturn vnum - 1;}
}void create_graph()
{ //to make the map of Beijing SubwayFILE *src = fopen("bgstations.txt", "r");int v1, v2; //v1 is the index of last station,v2 is the index of present stationint line_cnt;Vex tmp_vex;fscanf(src, "%d", &line_cnt);for (int i = 0; i < line_cnt; i++){int lineID, staion_cnt;fscanf(src, "%d%d", &lineID, &staion_cnt);v1 = v2 = -1;for (int j = 0; j < staion_cnt; j++){fscanf(src, "%s%d", tmp_vex.station_name, &tmp_vex.istransfer);v2 = add_vex(tmp_vex);if (v1 != -1){mat[v1][v2].weight = mat[v2][v1].weight = 1;mat[v1][v2].line = mat[v2][v1].line = lineID;}v1 = v2;}}fclose(src);
}int visited_dfs[MAXVEX] = {0};
void DFS(int i)
{printf("%s\n", v[i].station_name);visited_dfs[i] = 1;for (int j = 0; j < vnum; j++){if (mat[i][j].weight > 0 && visited_dfs[j] == 0){DFS(j);}}
}int sweight[MAXVEX]; //to record the shortest len between i and v0
int spath[MAXVEX]; //to record the shortest path
void Dijkstra(int v0)
{int minweight, minv;int wfound[MAXVEX] = {0}; //to sign if the shortest path from i to v0 is foundfor (int i = 0; i < vnum; i++){sweight[i] = mat[v0][i].weight;spath[i] = v0;wfound[i] = 0;}sweight[v0] = 0;wfound[v0] = 1;for (int i = 0; i < vnum - 1; i++){minweight = INF;for (int j = 0; j < vnum; j++){if (!wfound[j] && sweight[j] < minweight){minv = j;minweight = sweight[minv];}}wfound[minv] = 1;for (int j = 0; j < vnum; j++){if (!wfound[j] && (minweight + mat[minv][j].weight) < sweight[j]){sweight[j] = minweight + mat[minv][j].weight;spath[j] = minv;}}}
}
int final_path[MAXVEX] = {0};
int path_cnt = 0;
void reverse()
{int temple[MAXVEX] = {0};for (int i = 0; i < path_cnt; i++){temple[path_cnt - 1 - i] = final_path[i];}for (int i = 0; i < path_cnt; i++){final_path[i] = temple[i];}
}void put_path()
{int now, last, way_now, len;last = 0, now = 1;way_now = mat[final_path[last]][final_path[now]].line;len = 0;printf("%s", v[final_path[0]].station_name);for (; now < path_cnt; now++){if (way_now != mat[final_path[last]][final_path[now]].line){printf("-%d(%d)-%s", way_now, len, v[final_path[last]].station_name);way_now = mat[final_path[last]][final_path[now]].line;len = 0;}len++;last = now;}printf("-%d(%d)-%s", way_now, len, v[final_path[last]].station_name);
}int main()
{for (int i = 0; i < MAXVEX; i++){for (int j = 0; j < MAXVEX; j++){mat[i][j].weight = INF;mat[i][j].line = 0;}}create_graph();char begin[32], end[32];scanf("%s%s", begin, end);int index_b, index_e;//int flag1=0,flag2=0;for (int i = 0; i < vnum; i++){if (!strcmp(begin, v[i].station_name)){index_b = i;//flag1 = 1;}if (!strcmp(end, v[i].station_name)){index_e = i;//flag2 = 1;}}//DFS(0);//for(int i=0;i<vnum;i++) printf("%d %s\n",i,v[i].station_name);//printf("%d\n",vnum);/*for(int i=0;i<vnum;i++){for(int j=0;j<vnum;j++){if(mat[i][j].weight!=INF) printf("%d %d ",mat[i][j].line,mat[i][j].weight);}puts("");}*///printf("%d %d",flag1,flag2);//printf("\n%d %s\n",index_b,v[index_b].station_name);//printf("%d %s",index_e,v[index_e].station_name);Dijkstra(index_b);/*for(int i=0;i<vnum;i++) printf("%d ",spath[i]);*/int tmp = index_e;while (tmp != index_b){final_path[path_cnt++] = tmp;tmp = spath[tmp];}final_path[path_cnt++] = tmp;reverse();/*for(int i=0;i<path_cnt;i++){printf("%s ",v[final_path[i]].station_name);}*/put_path();
}
数据结构第七次作业·第四题·北京地铁线路查询Dijkstra算法相关推荐
- 攻防世界 Misc高手进阶区 6分题 北京地铁
前言 继续ctf的旅程 攻防世界Misc高手进阶区的6分题 本篇是北京地铁的writeup 发现攻防世界的题目分数是动态的 就仅以做题时的分数为准了 解题过程 题目描述 拿到一个bmp图片 扔进ste ...
- 北航(BUAA)数据结构第七次作业第二题 独立路径数计算
[问题描述] 老张和老王酷爱爬山,每周必爬一次香山.有次两人为从东门到香炉峰共有多少条路径发生争执,于是约定一段时间内谁走过对方没有走过的路线多谁胜. 给定一线路图(无向连通图,两顶点之间可能有多条边 ...
- 2021年人工神经网络第四次作业-第四题:旋转的数字
简 介: 本文对于作业中给定的机械数字字符识别问题进行了实验研究.通过对于采样1000样本的数据集合进行训练,经过增加DropOut的可以增加网络的泛化性能.对于网络规模的增加对训练精度没有明显的改进 ...
- 蓝桥杯java第七届决赛第四题--路径之谜
路径之谜小明冒充X星球的骑士,进入了一个奇怪的城堡.城堡里边什么都没有,只有方形石头铺成的地面.假设城堡地面是 n x n 个方格.[如图1.png]所示.按习俗,骑士要从西北角走到东南角.可以横向或 ...
- (王道408考研数据结构)第七章查找-第四节:哈希表(基本概念及其操作)
文章目录 一:哈希表基本概念 (1)哈希表 (2)建立一个简单的哈希表(快速入门以及相关术语) (3)ASL计算 二:常见哈希函数 (1)直接定址法 ( 常 考 ) _{(常考)}
- (王道408考研数据结构)第六章图-第四节5:最短路径之弗洛伊德算法(思想、代码、演示、答题规范)
文章目录 一:动态规划基本思想 二:弗洛伊德(Floyd)算法基本思想 三:弗洛伊德(Floyd)算法代码实现 四:弗洛伊德(Floyd)算法代码视频演示 五:弗洛伊德(Floyd)算法代码答题规范 ...
- 程序设计——第七周作业(Floyd:胜负未知场数;dijkstra:猫猫快线最快线路;SPFA:城市收税)
A-胜负未知场数 题目描述 众所周知,TT 有一只魔法猫. 这一天,TT 正在专心致志地玩<猫和老鼠>游戏,然而比赛还没开始,聪明的魔法猫便告诉了 TT 比赛的最终结果.TT 非常诧异,不 ...
- (王道408考研数据结构)第六章图-第四节3:最短路径之BFS算法(思想、代码、演示、答题规范)
文章目录 一:BFS算法基本思想 二:BFS算法代码 三:反思 最短路径shortestpath):主要有以下两类最短路径问题 单源最短路径问题:一个顶点到其他顶点最短路径 迪杰斯特拉算法(dijks ...
- 【算法学习笔记】 图(四)用优先级队列优化Dijkstra算法求最短路径(邻接矩阵存储)
优先级队列:priority_queue,经过实验之后发现默认是首先输出最大的元素,现在想让队头为最小的元素,需要进行运算符重载 此算法寻找源点到与它连接的所有顶点的最短路径 运算符重载: struc ...
- 【数据结构笔记24】单源最短路(迪克斯拉Dijkstra算法),多源最短路(弗洛伊德Floyd算法)
本次笔记内容: 7.1.1 概述 7.1.2 无权图的单源最短路 7.1.3 有权图的单源最短路 7.1.3-s 有权图的单源最短路示例 7.1.4 多源最短路算法 文章目录 最短路径问题 最短路径问 ...
最新文章
- django报错is not a registered tag library. Must be one of
- Oracle 表空间信息
- vs2010没有 最近使用的项目和解决方案
- 组建校园网计算机网络设计,小型校园网的设计与组建Word版
- wxWidgets:滚动Scrolling
- oracle精确匹配时间,Oracle时间精确到时、分、秒处理方法
- java gc full gc_Java中full gc什么意思?
- oracle查看锁表进程,杀掉锁表进程
- Apache java文件比对,Java Apache Commons的字符串比较
- linux查看正在运行的窗口,获取linux中打开的应用程序窗口的数量
- unity双击打不开脚本_游戏对象和脚本 (创建一个时钟)
- 项目部署—移除Spring Boot内置Tomcat,部署到云服务器Tomcat
- RPG JS跨平台测试
- 阿里云服务器对外开放tomcat端口访问
- 【编辑器】VSCode+TEXLIVE环境配置,以SJTUthesis为测试用例
- 橡胶柱压缩_橡胶=汽车半条命:浅谈ABAQUS橡胶大变形仿真5大注意事项
- Tomcat8zip版本安装与配置
- 华硕老毛子Padavan使用IPV6+Aliddns远程管理路由
- Contest1389 - 2018年第三阶段个人训练赛第四场.	售票(strncmp)
- zkSnarks:QAP上构造零知识证明
热门文章
- 往服务器复制文件提示拒绝访问,Win10系统复制文件提示目标文件夹被拒绝访问的解决方法...
- linux系统如何拨号上网连接,linux系统下怎样进行拨号上网?
- 关于 Private strand flush not complete
- linux无线蓝牙鼠标失效,无线蓝牙鼠标失灵怎么办 无线蓝牙鼠标失灵解决方法【详解】...
- FreeCodeCamp学习--Falsy Bouncer
- 聊聊校招内推,意义/优缺点/如何抓住机会等
- 【荣耀内推】2023届荣耀校招开启啦
- 剑指offer第9题及扩展 斐波那契数列
- OSChina 周日乱弹 —— 我重新说
- [RK3288][Android6.0] Audio中的HW Params设置流程