7-9 旅游規划(25 分)(Dijkstra最短路徑算法)


有了一張自駕旅游路線圖,你會知道城市間的高速公路長度、以及該公路要收取的過路費。現在需要你寫一個程序,幫助前來咨詢的游客找一條出發地和目的地之間的最短路徑。如果有若干條路徑都是最短的,那么需要輸出最便宜的一條路徑。

輸入格式:

輸入說明:輸入數據的第1行給出4個正整數N、M、S、D,其中N(2N500)是城市的個數,順便假設城市的編號為0~(N1);M是高速公路的條數;S是出發地的城市編號;D是目的地的城市編號。隨后的M行中,每行給出一條高速公路的信息,分別是:城市1、城市2、高速公路長度、收費額,中間用空格分開,數字均為整數且不超過500。輸入保證解的存在。

輸出格式:

在一行里輸出路徑的長度和收費總額,數字間以空格分隔,輸出結尾不能有多余空格。

輸入樣例:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

輸出樣例:

3 40

 

解題思路:1、很明顯這是一個圖的問題,但是它有兩個權值,因而我用了一個三元數組來存儲數據

                  2、又因其是單源最短路徑,因而使用Dijkstra算法

                  3、其次注意一下如果最短距離相同還要判斷費用是否最小

                 4、最后還要小心0也算是一個城市

 

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 
  4 #define MAXVEX 505
  5 #define INFINITY  65535
  6 
  7 void CreateGraph( );
  8 void Dijkstra( int v);
  9 
 10 
 11 int G[MAXVEX][MAXVEX][2],Nv,Ne;
 12 int know[MAXVEX];        //know[]=1表示求得最短路徑
 13 int distance[MAXVEX];   //表示求的最短距離
 14 int pay[MAXVEX];       //表示最少費用
 15 //int P[MAXVEX];        //存儲最短路徑的下標
 16 
 17 int main()
 18 {
 19     int s,d;
 20     scanf("%d %d %d %d",&Nv,&Ne,&s,&d);
 21     CreateGraph();
 22     Dijkstra(s);
 23     if( distance[d]<INFINITY ){
 24         printf("%d %d",distance[d],pay[d]);
 25     }
 26        
 27     return 0;
 28 }
 29 
 30 void CreateGraph()
 31 {
 32     //用鄰接矩陣表示圖
 33     int i,j;
 34     int v1,v2;
 35     int dn,f;  //dn表示距離,f表示費用
 36 
 37     for( i=0; i<Nv; i++)
 38     {
 39         for( j=0; j<Nv; j++)
 40         {
 41             G[i][j][0] = INFINITY;  //初始化
 42             G[i][j][1] = INFINITY;
 43         }
 44     }
 45 
 46     for( i=0; i<Ne; i++)  //注意這里是讀入邊
 47     {
 48         scanf("%d %d %d %d",&v1,&v2,&dn,&f);
 49         G[v1][v2][0] = G[v2][v1][0]=dn;
 50         G[v1][v2][1] = G[v2][v1][1]=f;
 51     }
 52 }
 53 
 54 void Dijkstra( int v)
 55 {
 56     //求從v結點到其他各結點的最短距離
 57     int i,j,k;
 58     int min,cost;
 59 
 60     for( i=0; i<Nv; i++)
 61     {
 62         know[i] =0;
 63         distance[i] =G[v][i][0];   //將與v點有連接的結點加上距離
 64         pay[i] =G[v][i][1];
 65     }
 66 
 67     know[v] = 1;
 68     distance[v] =0;   //V到V距離為0
 69     pay[v] = 0;
 70 
 71     for( i=1; i<Nv; i++)
 72     {
 73         min = INFINITY;     //當前所知離v結點的最近距離
 74         for( j=0; j<Nv; j++)
 75         {
 76             //尋找離v結點的最近距離
 77             if( !know[j] && distance[j]<min)
 78             {
 79                 k = j;
 80                 min = distance[j];
 81                 cost = pay[j];
 82             }
 83         }
 84 
 85         know[k] = 1;
 86         for( j=0; j<Nv; j++)
 87         {
 88             //修正最短路徑和距離
 89             if( !know[j] && (min+G[k][j][0]<distance[j]))
 90             {
 91                 distance[j] = min+G[k][j][0];
 92                 pay[j] = cost + G[k][j][1];
 93 
 94             }
 95             else if( !know[j] && (min+G[k][j][0]==distance[j]) && (cost+G[k][j][1] < pay[j]))
 96             {
 97 
 98                 pay[j] = cost + G[k][j][1];  
 99             }
100         }
101 
102     }
103 
104 }

 

以上是用鄰接矩陣存儲的,還有一種方法是使用鄰接表來實現,以下是用C++寫的,個人感覺更容易理解一些,空間復雜度也小一些

 1 #include<stdio.h>
 2 #include<queue>
 3 #include<vector>
 4 using namespace std;
 5 
 6 struct E
 7 {
 8     int next;
 9     int cost;
10     int dis;
11 };
12 vector<E> edge[501];
13 bool mark[501];
14 int dis[501];
15 int cost[501];
16 
17 int main()
18 {
19     int n,m,S,T;  //起點終點
20     int i,j;
21     E temp;
22     int newP;
23     while( scanf("%d%d%d%d",&n,&m,&S,&T)!=EOF)
24     {
25         if( n==0 && m==0) break;
26 
27         for( i=0; i<=n; i++)
28         {
29             edge[i].clear();   //初始化鄰接鏈表
30             dis[i] = -1;
31             mark[i] = false;
32             cost[i] = 0;
33         }
34         while( m--)
35         {
36             int a,b,d,c;
37             scanf("%d%d%d%d",&a,&b,&d,&c);
38             temp.cost = c;
39             temp.next = b;
40             temp.dis = d;
41             edge[a].push_back(temp);
42             temp.next = a;
43             edge[b].push_back(temp);  //無向圖,故每條邊信息都要添加到兩個頂點的單鏈表中
44         }
45 
46         dis[S] = 0;
47         mark[S] = 1;
48         newP = S;  //起點為s
49         for( i=1; i<n; i++)
50         {
51             for( j=0; j<edge[newP].size(); j++)
52             {
53                 //更新一個頂點對它的邊表內結點的距離
54                 int next = edge[newP][j].next;
55                 int c = edge[newP][j].cost;
56                 int d = edge[newP][j].dis;
57                 if( mark[next]==true) continue;
58                 if( dis[next]==-1 || dis[next]>dis[newP]+d
59                         || ((dis[next]==dis[newP]+d) &&(cost[next]>cost[newP]+c)))
60                 {
61                     dis[next] = dis[newP]+d;
62                     cost[next] = cost[newP]+c;
63                 }
64             }
65             int minx = 66666666;
66             for( j=0; j<=n; j++)
67             {
68                 //尋找這個頂點出發的最小值
69                 if( mark[j]==true) continue;
70                 if( dis[j]==-1) continue;
71                 if( dis[j]<minx)
72                 {
73                     minx = dis[j];
74                     newP = j;
75                 }
76             }
77             mark[newP] = true;
78         }
79         printf("%d %d\n",dis[T],cost[T]);
80     }
81     return 0;
82 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM