7-10 旅游規划 (25 分)
有了一張自駕旅游路線圖,你會知道城市間的高速公路長度、以及該公路要收取的過路費。現在需要你寫一個程序,幫助前來咨詢的游客找一條出發地和目的地之間的最短路徑。如果有若干條路徑都是最短的,那么需要輸出最便宜的一條路徑。
輸入格式:
輸入說明:輸入數據的第1行給出4個正整數N、M、S、D,其中N(2≤N≤500)是城市的個數,順便假設城市的編號為0~(N−1);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
Dijkstra算法 1.定義概覽 Dijkstra(迪傑斯特拉)算法是典型的單源最短路徑算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra算法是很有代表性的最短路徑算法,在很多專業課程中都作為基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。注意該算法要求圖中不存在負權邊。 問題描述:在無向圖 G=(V,E) 中,假設每條邊 E[i] 的長度為 w[i],找到由頂點 V0 到其余各點的最短路徑。(單源最短路徑) 2.算法描述 1)算法思想:設G=(V,E)是一個帶權有向圖,把圖中頂點集合V分成兩組,第一組為已求出最短路徑的頂點集合(用S表示,初始時S中只有一個源點,以后每求得一條最短路徑 , 就將加入到集合S中,直到全部頂點都加入到S中,算法就結束了),第二組為其余未確定最短路徑的頂點集合(用U表示),按最短路徑長度的遞增次序依次把第二組的頂點加入S中。在加入的過程中,總保持從源點v到S中各頂點的最短路徑長度不大於從源點v到U中任何頂點的最短路徑長度。此外,每個頂點對應一個距離,S中的頂點的距離就是從v到此頂點的最短路徑長度,U中的頂點的距離,是從v到此頂點只包括S中的頂點為中間頂點的當前最短路徑長度。 (1) 初始時,S只包含起點s;U包含除s外的其他頂點,且U中頂點的距離為"起點s到該頂點的距離"[例如,U中頂點v的距離為(s,v)的長度,然后s和v不相鄰,則v的距離為∞]。 (2) 從U中選出"距離最短的頂點k",並將頂點k加入到S中;同時,從U中移除頂點k。 (3) 更新U中各個頂點到起點s的距離。之所以更新U中頂點的距離,是由於上一步中確定了k是求出最短路徑的頂點,從而可以利用k來更新其它頂點的距離;例如,(s,v)的距離可能大於(s,k)+(k,v)的距離。 (4) 重復步驟(2)和(3),直到遍歷完所有頂點。
#include<iostream> #include<stdio.h> using namespace std; //距離表 struct { int visit; int len; int cost; }Visit[510]; //路線圖 struct { int len; int cost; }Graph[510][510]; //初始化路線圖,長度和過路費全初始化為999,相當於無窮 void InitGraph(int N) { for(int i=0; i<=N; i++) for(int j=0; j<=N; j++){ Graph[i][j].len = 999; Graph[i][j].cost = 999; } } //根據輸入的路線圖初始化距離表 //並且初始化源地到源地的距離和路費均為0 void InitVisit(int N, int S) { for(int i=0; i<=N; i++){ Visit[i].visit = 0; Visit[i].len = Graph[i][S].len; Visit[i].cost = Graph[i][S].cost; } Visit[S].visit = 1; Visit[S].cost = 0; Visit[S].len = 0; } //利用Dijkstra(迪傑斯特拉)算法計算源地到各地的距離最短 int DKS(int N, int S) { //循環 N-1 次找到這N-1個點到源點的距離最短 for(int j=1; j<N; j++){ //先找到一個距離最短的點 int MinPoint=N;//第N+1個點的距離已設置為999,相當於無窮 for(int i=0; i<N; i++){ if(!Visit[i].visit&&Visit[i].len<Visit[MinPoint].len){ MinPoint = i; } } if(MinPoint == N)//沒找到最短點,也就是完成循環,退出,可省略 break; Visit[MinPoint].visit = 1; for(int i=0; i<N; i++){ if(!Visit[i].visit){ //原點->中繼點->終點 < 原點->終點,更新最短距離 if(Visit[i].len>Visit[MinPoint].len+Graph[i][MinPoint].len){ Visit[i].len = Visit[MinPoint].len+Graph[i][MinPoint].len; Visit[i].cost = Visit[MinPoint].cost+Graph[i][MinPoint].cost; } //距離相同找花費更小的 if(Visit[i].len==Visit[MinPoint].len+Graph[i][MinPoint].len){ if(Visit[i].cost>Visit[MinPoint].cost+Graph[i][MinPoint].cost) Visit[i].cost=Visit[MinPoint].cost+Graph[i][MinPoint].cost; } } } } } int main() { int N, M, S, D; cin>>N>>M>>S>>D; InitGraph(N); int c1, c2, l, m; for(int i=0; i<M; i++){ cin>>c1>>c2>>l>>m; Graph[c1][c2].len = l; Graph[c1][c2].cost = m; Graph[c2][c1].len = l; Graph[c2][c1].cost = m; } InitVisit(N, S); DKS(N, S); cout<<Visit[D].len<<" "<<Visit[D].cost; }