设计实现一个全国大城市间的交通咨询程序,为旅客提供三种最优决策方案:
(1)飞行时间最短
(2)费用最小
(3)中转次数最少
数据如下:
机 号
出 发 地
到 达 地
出发时间
到达时间
费 用
6320
北京
上海
上海
北京
16:20
18:00
17:25
19:05
680元
2104
北京
乌鲁木齐
乌鲁木齐
北京
8:00
10:45
9:55
11:40
1150元
201
北京
西安
西安
北京
15:25
12:35
17:00
14:15
930元
2323
西安
广州
广州
西安
7:15
10:15
9:35
11:35
1320元
173
拉萨
昆明
昆明
拉萨
10:20
12:35
11:45
14:00
830元
3304
拉萨
武汉
武汉
拉萨
14:15
16:25
15:45
17:55
890元
82
乌鲁木齐
昆明
昆明
乌鲁木齐
9:30
13:05
12:15
15:50
1480元
4723
武汉
广州
广州
武汉
7:05
11:25
8:45
13 :05
810元
这是一道数据结构的题目,知识点为数据结构中的图,利用迪杰斯特拉(Dijkstra)算法求解单源路径最短问题。
关于Dijkstra算法的思路:
1.将图上的初始点看作一个集合S,其它点看作另一个集合
2.根据初始点,求出其它点到初始点的距离d[i] (若相邻,则d[i]为边权值;若不相邻,则d[i]为无限大)
3.选取最小的d[i](记为d[x]),并将此d[i]边对应的点(记为x)加入集合S
(实际上,加入集合的这个点的d[x]值就是它到初始点的最短距离)
4.再根据x,更新跟 x 相邻点 y 的d[y]值:d[y] = min{ d[y], d[x] + 边权值w[x][y] },因为可能把距离调小,所以这个更新操作叫做松弛操作。
( 因为第三步只更新并确定了x点到初始点的最短距离,集合内其它点是之前加入的,也经历过第 4 步,所以与 x 没有相邻的点的 d 值是已经更新过的了,不会受到影响)
5.重复3,4两步,直到目标点也加入了集合,此时目标点所对应的d[i]即为最短路径长度。
具体操作可以看这个例子,动图很快,最好自己动手一步一步地操作一遍就大概懂了
声明:这里的Dijkstra算法讲解参考了另一位博主的文章,链接如下https://blog.csdn.net/Kprogram/article/details/81225176
下面开始编程思路分析:
查询8个城市中任意城市到其他城市的最低价,最短时间和最短路径信息,也就是对8个不同数据元进行三种不同的操作。而这三个操作又有共同特点,查询最短距离,最低价格,最短时间,都是求图中一个顶点到其他所有顶点的最短距离,只是权值不一样,核心都是单源路径最短问题,用的算法都是Dijkstra算法。所以可以单独写一个迪杰斯特拉算法,根据三种不同需求,传入边权值,返回对应的最短路径。这样避免了代码的重复。
代码演示:
头文件MGraph.h
#include <stdio.h>
#define maxVertices 30 //图中顶点数目的最大值
#define maxEdges 900 //最大边数
#define maxWeight 32767
#define impossibleVablue '#'
#define impossibleWeight -1
typedef int Type; //顶点数据的数据类型
typedef int Weight; //边上权值的数据类型
typedef struct{
int numVertices,numEdges; //图中实际顶点个数和边的条数
Type VerticesList[maxVertices]; //顶点表
Weight Edge[maxVertices][maxVertices]; //邻接矩阵
}MGraph;
int getVertexPos(MGraph& G,Type x) //从顶点的数据值找出该顶点的顶点号,如果查找失败,返回-1
{
for(int i=0;i<G.numVertices;i++)
{
if(G.VerticesList[i]==x)
return i;
}
return -1;
}
int numberOfVertices(MGraph& G) //返回图中当前已有的顶点个数
{
return G.numVertices;
}
void createMGraph(MGraph& G,Type v[],int n,Type ed[][2],Weight c[],int e) //顶点数据存放在v[],边的顶点对分别存放于ed[e][0],ed[e][1],权值存放在c[e]
{
G.numVertices=n;G.numEdges=e;
int i,j,k;
for(i=0;i<G.numVertices;i++) //初始化
{
G.VerticesList[i]=v[i];
for(j=0;j<G.numVertices;j++)
G.Edge[i][j]=(i==j) ? 0:maxWeight; //初始化邻接矩阵
}
for(k=0;k<G.numEdges;k++) //建立邻接矩阵
{
i=getVertexPos(G,ed[k][0]); //使用ed[][]将顶点值转换为顶点号,建立图
j=getVertexPos(G,ed[k][1]);
G.Edge[i][j]=c[k]; //边赋值
}
}
void ShortestPath(MGraph& G,int v,Weight dist[],int path[])//dist[j]存放当前求到的从顶点v到顶点j的最短路径长度,path[j]存放求到的最短路径长度
{
int n=numberOfVertices(G);
int S[maxVertices];//最短路径顶点集
int i,j,k;
Weight w,min;
for(i=0;i<n;i++)
{
dist[i]=G.Edge[v][i];
S[i]=0;
if(i!=v&&dist[i]<maxWeight)
path[i]=v;
else
path[i]=-1;
}
S[v]=1; dist[v]=0; //顶点v加入S集合
for(i=0;i<n-1;i++)
{
min=maxWeight;
int u=v;
for(j=0;j<n;j++)
if(!S[j]&&dist[j]<min){
u=j;
min=dist[j];
}
S[u]=1;
for(k=0;k<n;k++){
w=G.Edge[u][k];
if(!S[k]&&w < maxWeight && dist[u]+w < dist[k])
{
dist[k]=dist[u]+w;
path[k]=u;//顶点k未加入S,且绕过u可以缩短路径
}
}
}
}
void printShortestPath_price(MGraph& G,int v,Weight dist[],int path[])
{
printf("从城市[%d]到其他城市的费用为:\n",G.VerticesList[v]);
int i,j,k,n=numberOfVertices(G);
int d[maxVertices];
for(i=0;i<n;i++) //逐个顶点输出v0-vi最短路径
if(i!=v){
j=i;k=0;
while(j!=v){
d[k++]=j;
j=path[j];
}
d[k++]=v;
printf("到城市[%d]的最短路径长度为:",G.VerticesList[i]);
while(k>0)
printf("%d",G.VerticesList[d[--k]]);
printf("\n费用为:%d元\n",dist[i]);
}
}
void printShortestPath_time(MGraph& G,int v,Weight dist[],int path[])
{
printf("从城市[%d]到其他城市的飞行时间为:\n",G.VerticesList[v]);
int i,j,k,n=numberOfVertices(G);
int d[maxVertices];
for(i=0;i<n;i++)
if(i!=v){
j=i;k=0;
while(j!=v){
d[k++]=j;
j=path[j];
}
d[k++]=v;
printf("到城市[%d]的最短路径长度为:",G.VerticesList[i]);
while(k>0)
printf("%d",G.VerticesList[d[--k]]);
printf("\n飞行时间为:%d\n",dist[i]);
}
}
void printShortestPath_num(MGraph& G,int v,Weight dist[],int path[])
{
printf("从城市[%d]到其他城市的中转次数为:\n",G.VerticesList[v]);
int i,j,k,n=numberOfVertices(G);
int d[maxVertices];
for(i=0;i<n;i++)
if(i!=v){
j=i;k=0;
while(j!=v){
d[k++]=j;
j=path[j];
}
d[k++]=v;
printf("到城市[%d]的最短路径长度为:",G.VerticesList[i]);
while(k>0)
printf("%d",G.VerticesList[d[--k]]);
printf("\n中转次数为:%d\n",dist[i]-1);
}
}
主函数main.cpp
#include "MGraph.h"
#include <iostream>
using namespace std;
int main()
{
MGraph G;
int location,operation;
int n=8,e=16;
int path[20];
Type v[8]={0,1,2,3,4,5,6,7};
Type ed[16][2]={0,1,1,0,0,2,2,0,0,3,3,0,3,4,4,3,5,6,6,5,5,7,7,5,2,6,6,2,7,4,4,7}; //存储图中的链接情况,数值为各个地点的编号,16组是因为8对顶点,相互有16个关系。
Weight a[16]={680,680,1150,1150,930,930,1320,1320,830,830,890,890,1480,1480,810,810}; //价格权值
Weight b[16]={65,65,115,115,95,95,140,140,85,85,90,90,165,165,100,100}; //时间权值
Weight c[16]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; //中转次数权值
Weight dist[100];
cout <<"请输入开始的城市(0:北京,1:上海:2:乌鲁木齐,3:西安,4:广州,5:拉萨,6:昆明,7:武汉):"<<endl;
cin >> location;
cout << "请输入选择的操作(1:查询最低价格,2:查询最短飞行时间,3:中转次数最少):" << endl;
cin >> operation;
switch(operation){
case 1:{
createMGraph(G,v,n,ed,a,e);
ShortestPath(G,location,dist,path);
printShortestPath_price(G,location,dist,path);
break;}
case 2:{
createMGraph(G,v,n,ed,b,e);
ShortestPath(G,location,dist,path);
printShortestPath_time(G,location,dist,path);
break;}
case 3:{
createMGraph(G,v,n,ed,c,e);
ShortestPath(G,location,dist,path);
printShortestPath_num(G,location,dist,path);
break;}
default:
break;
}
return 0;
}
在同一个文件夹下运行,得到结果为:
路径数字为城市代码的顺序