//使用前将bgstations.txt(文件的内容在代码末尾)放在与cpp文件的同一位置
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>
#define MAX 9999
#define N 20 /*最长站名*/
#define NUM 599 /*最大站数*/
typedef struct{ /*车站信息*/
char station[N]; /*站名称*/
int change; /*换乘状态,1为是,0为否*/
}sta;
typedef struct{ /*相邻两站信息*/
int weight; /*两站之间的距离为1*/
int L; /*两站所在的线号*/
}G;
sta vertex[NUM]; /*地铁图顶点数组*/
G graph[NUM][NUM]; /*图权重数组*/
int Vsum; /*实际地铁站数*/
int path[NUM]; /*换乘路径*/
int s[NUM]; /*起始站到其它站最短路是否找到*/
int dis[NUM]; /*起始站到其他站的最短距离*/
int cout[NUM]; /*存储路径的栈*/
int top=-1;
/*---------------------------------------------------*/
void push(int v);
int empty();
int pop();
int search(char *s);
void create(int LINE);
void dijkstra(int V1,int V2);
void floyd(int V1,int V2);
void print(int V1,int V2);
void make();
void program();
/*---------------------------------------------------*/
void push(int v){/*入栈*/
if(top==NUM) return;
cout[++top]=v;
}
int empty(){/*栈是否为空*/
if(top<0) return 1;
return 0;
}
int pop(){/*出栈*/
if(empty())return -1;
return cout[top--];
}
int search(char *s){/*查找站是否存在*/
int i;
for(i=0;i<Vsum;i++)
if(!strcmp(vertex[i].station,s))
return i;
return -1;
}
void create(int LINE){/*建图*/
while(LINE--){
int no,sum; /*每条线路的编号和站数*/
scanf("%d %d ",&no,&sum);
printf("\n%d号线 共%d个站\n\n",no,sum);
int last=-1; /*上一站*/
while(sum--){ /*存储时注意站会重复*/
char name[N];
int is;
scanf("%s %d ",name,&is);
if(is==1){
printf("%s(换乘) -> ",name);
}else{
printf("%s -> ",name);
}
/*查找该站是否已存在*/
int index=search(name);
if(index==-1){ /*不存在*/
strcpy(vertex[Vsum].station, name);
vertex[Vsum].change=is;
if(last!=-1){
graph[last][Vsum].L=graph[Vsum][last].L=no;
graph[last][Vsum].weight=graph[Vsum][last].weight=1;
}
last=Vsum; /*更新上一站*/
Vsum++; /*更新顶点*/
}else{ /*存在*/
if(last!=-1){
graph[last][index].L=graph[index][last].L=no;
graph[last][index].weight=graph[index][last].weight=1;
}
last=index; /*更新上一站*/
}
}
printf("\n");
}
}
//迪杰斯特拉算法
void dijkstra(int V1,int V2){
int i;
/*初始化*/
for(i=0;i<Vsum;i++){
dis[i]=graph[V1][i].weight;
s[i]=0;
path[i]=V1;
}
dis[V1]=0;
s[V1]=1;
int minweight,v=-1,j;
for(i=0;i<Vsum-1;i++){
minweight=MAX;
/*找到未标记的最小权重值顶点 */
for(j=0;j<Vsum;j++){
if(!s[j]&&dis[j]<minweight){
v=j;
minweight=dis[v];
}
}
s[v]=1; /*标记顶点已找到最短路*/
if(v==V2) return; /*终点已标记则返回*/
for(j=0;j<Vsum;j++){
if(!s[j]&&graph[v][j].L&&minweight+graph[v][j].weight<dis[j]){
dis[j]=minweight+graph[v][j].weight;
path[j]=v; /*记录路径的前驱顶点*/
}
}
}
}
//弗洛伊德算法
void floyd(int V1,int V2){
int i,j,k;
int p_ath[NUM][NUM];
/*初始化路径*/
for(i=0;i<Vsum;i++)
for(j=0;j<Vsum;j++)
if(i!=j&&graph[i][j].weight<MAX)
p_ath[i][j]=i;
for(k=0;k<Vsum;k++)
for(i=0;i<Vsum;i++)
for(j=0;j<Vsum;j++)
if(graph[i][j].weight>graph[i][k].weight+graph[k][j].weight){
graph[i][j].weight=graph[i][k].weight+graph[k][j].weight;
p_ath[i][j]=p_ath[k][j];
}
int t=V2;
for(;t!=V1;t=p_ath[V1][t]) /*路径追溯*/
push(t);
}
void print(int V1,int V2){
int last=V1; /*保存上一站*/
int k=1; /*乘坐站数*/
int u=pop(); /*下一站*/
int L=graph[last][u].L; /*乘坐线路*/
printf("最佳方案:%s-%d号线(",vertex[V1].station,L);
last=u; /*更新上一站*/
while(!empty()){
u=pop();
if(L!=graph[last][u].L){ /*需要换乘*/
L=graph[last][u].L;
/*打印乘坐站数和此换乘站*/
printf("共%d站)-%s-%d号线(",k,vertex[last].station,L);
k=0;
}
k++;
last=u; /*更新上一站*/
}
printf("共%d站)-%s\n",k,vertex[V2].station);
}
void dp(int V1,int V2){
int f[NUM]={MAX},p_ath[NUM]={V1};
f[Vsum-1]=0;
int i,j;
for(i=Vsum-2;i>=0;i--){
for(j=i+1;j<Vsum;j++){
if(f[j]<MAX&&graph[i][j].weight+f[j]<f[i]){
f[i]=graph[i][j].weight+f[j];
p_ath[i]=j;
}
}
}
int t=V2;
for(;t!=V1;t=p_ath[t]) push(t);
}
/*---------------------------------------------------*/
void make(){
printf("\n-----北京地铁乘坐线路查询系统-----\n");
printf("\n1.查询线路\n");
printf("2.退出查询\n");
int op;
printf("请输入:");
scanf("%d",&op);
if(op==1) program();
else{
printf("\n欢迎下次使用!\n");
return;
}
}
void program(){
int V1,V2;
printf("请输入起始站名和终点站名,两站之间用回车分开\n");
/*输入起始站和终点站*/
char name_start[N],name_end[N];
scanf("%s %s",name_start,name_end);
printf("\n");
V1=search(name_start);
V2=search(name_end);
/*---------------------------------------------------*/
/*查询换乘*/
dijkstra(V1,V2);
int t=V2;
for(;t!=V1;t=path[t]) push(t); /*路径追溯*/
//floyd(V1,V2);
//dp(V1,V2);
/*打印结果*/
print(V1,V2);
make();
}
int main(){
freopen("bgstations.txt","r",stdin);
int LINE; /*地铁总线数*/
scanf("%d ",&LINE);
int i,j;
/*初始化*/
for(i=0;i<NUM;i++)
for(j=0;j<NUM;j++){
graph[i][j].weight=graph[j][i].weight=MAX;
graph[i][j].L=graph[j][i].L=0;
}
/*---------------------------------------------------*/
/*建图*/
create(LINE);
freopen("CON", "r", stdin);
/*--------------------------------------------------*/
/*查找起始站与终点站对应的顶点编号*/
make();
system("pause");
return 0;
}
bgstations.txt中的内容:
12
1 23
苹果园 0
古城 0
八角游乐园 0
八宝山 0
玉泉路 0
五棵松 0
万寿路 0
公主坟 1
军事博物馆 1
木樨地 0
南礼士路 0
复兴门 1
西单 1
天安门西 0
天安门东 0
王府井 0
东单 1
建国门 1
永安里 0
国贸 1
大望路 1
四惠 1
四惠东 1
2 19
西直门 1
积水潭 0
鼓楼大街 1
安定门 0
雍和宫 1
东直门 1
东四十条 0
朝阳门 1
建国门 1
北京站 0
崇文门 1
前门 0
和平门 1
宣武门 1
长椿街 0
复兴门 1
阜成门 0
车公庄 1
西直门 1
4 24
安河桥北 0
北宫门 0
西苑 0
圆明园 0
北京大学东门 0
中关村 0
海淀黄庄 1
人民大学 0
魏公村 0
国家图书馆 1
动物园 0
西直门 1
新街口 0
平安里 1
西四 0
灵境胡同 0
西单 1
宣武门 1
菜市口 1
陶然亭 0
北京南站 1
马家堡 0
角门西 1
公益西桥 1
5 23
宋家庄 1
刘家窑 0
蒲黄榆 1
天坛东门 0
磁器口 1
崇文门 1
东单 1
灯市口 0
东四 1
张自忠路 0
北新桥 0
雍和宫 1
和平里北街 0
和平西桥 0
惠新西街南口 1
惠新西街北口 0
大屯路东 1
北苑路北 0
立水桥南 0
立水桥 1
天通苑南 0
天通苑 0
天通苑北 0
6 27
海淀五路居 0
慈寿寺 1
花园桥 0
白石桥南 1
车公庄西 0
车公庄 1
平安里 1
北海北 0
南锣鼓巷 1
东四 1
朝阳门 1
东大桥 0
呼家楼 1
金台路 1
十里堡 0
青年路 0
褡裢坡 0
黄渠 0
常营 0
草房 0
物资学院路 0
通州北关 0
通运门 0
北运河西 0
郝家府 0
东夏园 0
潞城 0
7 20
北京西站 1
湾子 0
达官营 0
广安门内 0
菜市口 1
虎坊桥 0
珠市口 0
桥湾 0
磁器口 1
广渠门内 0
广渠门外 0
九龙山 1
大郊亭 0
百子湾 0
化工 0
南楼梓庄 0
欢乐谷景区 0
垡头 0
双合 0
焦化厂 0
8 18
朱辛庄 1
育知路 0
平西府 0
回龙观东大街 0
霍营 1
育新 0
西小口 0
永泰庄 0
林萃桥 0
森林公园南门 0
奥林匹克公园 1
奥体中心 0
北土城 1
安华桥 0
安德里北街 0
鼓楼大街 1
什刹海 0
南锣鼓巷 1
9 13
郭公庄 1
丰台科技园 0
科怡路 0
丰台南路 0
丰台东大街 0
七里庄 1
六里桥 1
六里桥东 0
北京西站 1
军事博物馆 1
白堆子 0
白石桥南 1
国家图书馆 1
10 46
巴沟 0
苏州街 0
海淀黄庄 1
知春里 0
知春路 1
西土城 0
牡丹园 0
健德门 0
北土城 1
安贞门 0
惠新西街南口 1
芍药居 1
太阳宫 0
三元桥 1
亮马桥 0
农业展览馆 0
团结湖 0
呼家楼 1
金台夕照 0
国贸 1
双井 0
劲松 0
潘家园 0
十里河 1
分钟寺 0
成寿寺 0
宋家庄 1
石榴庄 0
大红门 0
角门东 0
角门西 1
草桥 0
纪家庙 0
首经贸 0
丰台站 0
泥洼 0
西局 1
六里桥 1
莲花桥 0
公主坟 1
西钓鱼台 0
慈寿寺 1
车道沟 0
长春桥 0
火器营 0
巴沟 0
13 16
西直门 1
大钟寺 0
知春路 1
五道口 0
上地 0
西二旗 1
龙泽 0
回龙观 0
霍营 1
立水桥 1
北苑 0
望京西 1
芍药居 1
光熙门 0
柳芳 0
东直门 1
14 26
张郭庄 0
园博园 0
大瓦窑 0
郭庄子 0
大井 0
七里庄 1
西局 1
北京南站 1
永定门外 0
景泰 0
蒲黄榆 1
方庄 0
十里河 1
北工大西门 0
九龙山 1
大望路 1
金台路 1
枣营 0
东风北桥 0
将台 0
望京南 0
阜通 0
望京 1
东湖渠 0
来广营 0
善各庄 0
15 19
俸伯 0
顺义 0
石门 0
南法信 0
后沙峪 0
花梨坎 0
国展 0
孙河 0
马泉营 0
崔各庄 0
望京 1
望京西 1
关庄 0
大屯路东 1
安立路 0
奥林匹克公园 1
北沙滩 0
六道口 0
清华东路西口 0