設計實現一個全國大城市間的交通諮詢程序,爲旅客提供三種最優決策方案:
(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;
}
在同一個文件夾下運行,得到結果爲:
路徑數字爲城市代碼的順序