【问题描述】
编写一个程序实现北京地铁最短乘坐(站)线路查询,输入为起始站名和目的站名,输出为从起始站到目的站的最短乘坐站换乘线路。注: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站至北京西站”。本样例存在两条最少站数的乘坐方式,只要找出一条就可以。
【评分标准】
对于同一个起始站和目的站,如果存在多条最少站数的乘坐方式,只要找出其中一条就可以。测试点全通过得满分。
下面上代码:
#include
#include
#define max_length 20//表示字符串长度
#define max_station 500//表示最多地铁站数
#define INFINITY 32767//大数
struct station{
char name[max_length];//站点名称
int state;//换乘状态,0 非换乘,1 换乘
}sta[max_station];
//存站点
struct weight{
int wei;//权重,可以理解为两站点之间的相差站数
int line;//两站点间的线路所在线号
}vertex[max_station+5][max_station+5];
//存边权重
FILE *in;
int k,spath[max_station];//spath[]数组存路径
void read(){
in=fopen("bgstations.txt","r");
int max_line;
fscanf(in,"%d",&max_line);
int i,j,v1,v2;
//初始化
for(i=1;i<=max_station;i++){
for(j=1;j<=max_station;j++){
vertex[i][j].wei=INFINITY;
vertex[i][j].line=0;
}
}//初始化结束
/* 初始化很重要,曾多次掉坑 */
for(i=1;i<=max_line;i++){
int line_num,station_num;
v1=v2=-1;//表示前后两个站点
fscanf(in,"%d%d",&line_num,&station_num);
for(j=1;j<=station_num;j++){
//判断该站点是否是之前读过
char s[max_station];
int ii,flag=1,change;
fscanf(in,"%s%d",s,&change);
for(ii=1;ii<=k;ii++){
if(strcmp(sta[ii].name,s)==0){//读过
flag=0;
v1=ii;
break;
}
}
if(flag){//没读过
k++;
strcpy(sta[k].name,s);
sta[k].state=change;
v1=k;
}
if(v2!=-1){//表示当前读入的v1点不是该线路的第一个点
vertex[v1][v2].line=vertex[v2][v1].line=line_num;
vertex[v1][v2].wei=vertex[v2][v1].wei=1;
}
v2=v1;//记录当前点,之后读入可以用来比较
}
}
fclose(in);
}
//Dijkstra算法
void Dijkstra(int origion,int destination){
int i,j,v=0;
int minweight;
int found[max_station+5]; // 标记是否已经确定最短距离
memset(found,0,sizeof(found[0])*max_station); // 初始化
int sweight[max_station+5]; // 存最短距离
for(i=1;i<=max_station;i++){ // 初始化
sweight[i]=vertex[origion][i].wei;
spath[i]=origion;// i 的前驱结点为 origion
}
sweight[origion]=0;//标记距离
found[origion]=1;//标记已找到
for(i=1;i0) && (minweight+vertex[v][j].wei=1;i--){
if(flag == 0) {
printf("%s-%d",sta[temp[i]].name,vertex[temp[i]][temp[i-1]].line);
flag=1;
}
else{
if(vertex[temp[i+1]][temp[i]].line==vertex[temp[i]][temp[i-1]].line){
cnt++;
}
else{
printf("(%d)-",cnt);
cnt=1;
flag=0;
i++;
}
}
}
printf("(%d)-%s\n",cnt,sta[destination].name);
}
int main()
{
read();
char start[max_length],end[max_length];
scanf("%s%s",start,end);
int origion=0,destination=0,cnt=0;
int i;
for(i=1;i<=k;i++){
if(strcmp(sta[i].name,start) = = 0){
origion=i;
cnt++;
}
if(strcmp(sta[i].name,end) = = 0){
destination=i;
cnt++;
}
if(cnt==2) break;
}
Dijkstra(origion,destination);
print(origion,destination);
return 0;
}
以上就是全部代码,由于刚刚接触算法,所以对Dijkstra算法并不熟悉,特记在此,便于日后回顾总结。