铁路交通网的最短路径
在有向图表示的铁路网中,利用Dijkstra算法,求出从指定的起点城市到终点城市的最短路径,并输出。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define LISTINITSIZE 20
#define INF __DBL_MAX__ //双精度浮点数最大值
typedef int Status;
typedef char *VertexType;//顶点信息类型(城市名)
typedef struct ArcNode{ //邻接表的一条边
int adjvex;
struct ArcNode *nextarc;
double weight; //边权
}ArcNode;
typedef struct VNode{ //一个顶点
VertexType data;
ArcNode *firstarc;
}VNode,*AdjList;
typedef struct{
AdjList vertices; //顶点线性表
int vexnum; //顶点数
}ALGraph;
int Dijkstra(int start,int des,ALGraph G,int **path,double *cost);
void InitMap(ALGraph *G,char* filename);
double Weight(ALGraph G,int i,int j);
void PrintPath(ALGraph G,int *path,int n,double cost);
void PrintMap(ALGraph G);
int main(){
int start,des,n,*path;
double cost=0;
char *filename="graph.txt";
ALGraph map;
system("cls");
printf("<路径规划>\n加载地图: %s\n",filename);
InitMap(&map,filename);
n=map.vexnum;
PrintMap(map);
printf("请输入起点与终点编号(从1开始):");
scanf("%d%d",&start,&des);
if(start==des||start>n||start<=0||des>n||des<=0){
printf("路径不可用!\n");
exit(ERROR);
}
n=Dijkstra(start-1,des-1,map,&path,&cost);
PrintPath(map,path,n,cost);
system("pause");
}
void InitMap(ALGraph *G,char* filename){ //读取地图信息
//#格式:编号 城市名 相连城市编号1 相连城市1距离 ... 【换行符】
//编号从1开始,每一行以-1结尾
FILE *fp=NULL;
int i,n;
ArcNode *p;
if(!(fp=fopen(filename,"r"))) exit(ERROR);
fscanf(fp,"%d",&G->vexnum); //第一个数据为总顶点数量
if(G->vexnum<=0) exit(ERROR); //数据个数有误
if(!((G->vertices)=(AdjList)calloc(G->vexnum,sizeof(VNode)))) exit(OVERFLOW);//分配顶点线性表空间
for(i=0;i<G->vexnum&&!feof(fp);i++){
fscanf(fp,"%d",&n);
if(!(G->vertices[i].data=(VertexType)calloc(LISTINITSIZE,sizeof(char)))) exit(OVERFLOW);
G->vertices[i].firstarc=NULL;
fscanf(fp,"%s %d",G->vertices[i].data,&n);
while(n>0&&!feof(fp)){
if(!(p=(ArcNode*)malloc(sizeof(ArcNode)))) exit(OVERFLOW);
p->nextarc=G->vertices[i].firstarc;
G->vertices[i].firstarc=p; //头插法
fscanf(fp,"%lf",&p->weight);
p->adjvex=n-1;
fscanf(fp,"%d",&n);
}
}
if(i!=G->vexnum) exit(ERROR);//地图数据缺少
fclose(fp);
}
int Dijkstra(int start,int des,ALGraph G,int **path,double *cost){//Dijkstra算法规划路径,最后输出一个以-1结尾的整形数组
int final[G.vexnum];//是否到达过各点
double D[G.vexnum];//到各点的最短距离
int Pre[G.vexnum];
//记录从start到i顶点的路径中,i顶点的前一个顶点的下标
int i,j,v;
double min,a;
ArcNode *p;
for(i=0;i<G.vexnum;i++){
final[i]=FALSE;
D[i]=INF;
Pre[i]=start;
}
for(p=G.vertices[start].firstarc;p;p=p->nextarc) D[p->adjvex]=Weight(G,start,p->adjvex);
final[start]=TRUE;
for(i=1;i<G.vexnum;i++){//i是计数器
min=INF;
for(j=0;j<G.vexnum;j++){//选出距离最小的j
if(final[j]==FALSE&&D[j]<min){//若未访问过且有弧相连
v=j;
min=D[j];
}
}//for
final[v]=TRUE;
if(v==des) break; //已经找到路径
for(j=0;j<G.vexnum;j++){
if(final[j]==FALSE&&((a=Weight(G,v,j))<D[j]-min)){
D[j]=a+min;
Pre[j]=v;
}
}
}
*cost=D[des];
int inversepath[G.vexnum]; //终点到起点的路径,线性栈(由于Pre数组是倒序查找的)
inversepath[0]=des;
for(i=1,j=Pre[des];i<G.vexnum&&j!=start;i++,j=Pre[j]) inversepath[i]=j;
inversepath[i]=start;
if(!(*path=(int *)calloc(i+1,sizeof(int)))) exit(OVERFLOW);
for(j=0;i>=0;j++,i--) (*path)[j]=inversepath[i];
return j;
}
double Weight(ALGraph G,int i,int j)
{
ArcNode *p;
if(i==j) return 0.0;
for(p=G.vertices[i].firstarc;p;p=p->nextarc) if(p->adjvex==j) break;
if(!p) return INF;
return p->weight;
}
void PrintPath(ALGraph G,int *path,int n,double cost)//输出路径
{
int i;
printf("从 %s 到 %s 的最短路径为: %s",G.vertices[path[0]].data,G.vertices[path[n-1]].data,G.vertices[path[0]].data);
for(i=1;i<n;i++) printf("->%s",G.vertices[path[i]].data);
putchar('\n');
printf("总距离: %g km\n",cost);
}
void PrintMap(ALGraph G){ //打印地图数据
int i;
ArcNode *p;
printf("地图加载完成:\n");
for(i=0;i<G.vexnum;i++){
printf("顶点%d: %s; 相连:",i+1,G.vertices[i].data);
if(!(p=G.vertices[i].firstarc)) printf(" 不存在");
while(p){
printf(" 顶点%d,距离%g;",p->adjvex+1,p->weight);
p=p->nextarc;
}
putchar('\n');
}
}