資料結構實驗之圖論七:驢友計劃__Dijkstra
阿新 • • 發佈:2018-12-09
Problem Description
做為一個資深驢友,小新有一張珍藏的自駕遊線路圖,圖上詳細的標註了全國各個城市之間的高速公路距離和公路收費情況,現在請你編寫一個程式,找出一條出發地到目的地之間的最短路徑,如果有多條路徑最短,則輸出過路費最少的一條路徑。
Input
連續T組資料輸入,每組輸入資料的第一行給出四個正整數N,M,s,d,其中N(2 <= N <= 500)是城市數目,城市編號從0~N-1,M是城市間高速公路的條數,s是出發地的城市編號,d是目的地的城市編號;隨後M行,每行給出一條高速公路的資訊,表示城市1、城市2、高速公路長度、收費額,中間以空格間隔,數字均為整數且不超過500,輸入資料均保證有解。
Output
在同一行中輸出路徑長度和收費總額,資料間用空格間隔。
Sample Input
1
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
Sample Output
3 40
AC程式碼:
#include<bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; struct node { int len,mon; } mp[501][501]; int main() { int T,n,m,s,d,u,v,l,w; cin>>T; while(T--) { cin>>n>>m>>s>>d; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { if(i==j) { mp[i][j].len=0; mp[i][j].mon=0; } else { mp[i][j].len=INF; mp[i][j].mon=INF; } } } for(int i=0; i<m; i++) { cin>>u>>v>>l>>w; mp[u][v].len=mp[v][u].len=l; mp[u][v].mon=mp[v][u].mon=w; } for(int k=0; k<n; k++) { for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { if(mp[i][j].len>mp[i][k].len+mp[k][j].len) { mp[i][j].len=mp[i][k].len+mp[k][j].len; mp[i][j].mon=mp[i][k].mon+mp[k][j].mon; } else if(mp[i][j].len==mp[i][k].len+mp[k][j].len) { if( mp[i][j].mon>mp[i][k].mon+mp[k][j].mon) { mp[i][j].mon=mp[i][k].mon+mp[k][j].mon; } } } } } cout<<mp[s][d].len<<" "<<mp[s][d].mon<<endl; } return 0; }
轉__Dijkstra
#include<bits/stdc++.h> #define MAX INT_MAX //int型裡面最大的數 using namespace std ; int n, m ; //頂點數,邊數; int Map[550][550] ; //存放點與點之間的權值; int vis[550] ; //點的訪問情況 ; int money[550][550] ; //存放點與點之間的過路費 ; void Dijkstra(int n, int v0, int vn) { int dist[550] ; //存放v0到vn的最短路徑 ; int mon[550] ; for(int i=0; i<n; i++) { dist[i] = Map[v0][i] ; //每個點的最短路徑都設為與起點相連邊上的權值,(不與起點相連的點dist[]陣列的值為MAX) mon[i] = money[v0][i] ;//每個點的過路費都初始化成與起點v0相連邊上的費用。 } vis[v0] = 1 ; //---->| dist[v0] = 0 ; // |---->對起點的初始化。 mon[v0] = 0 ; //----->| for(int i=1; i<n; i++) //除了起點一共n-1個點 ; { int MIN = MAX ; //先取一個無窮大的數,可以方便以後的替換其他的值; int k = v0 ; //記錄最短路徑相關點的下標; for(int j=0 ; j<n ; j++) //找出與起始點相連最短的路徑; { if(vis[j]==0&&dist[j]<MIN) //如果這個點沒有被訪問過,而且這個點的最短路徑比min小;(這個迴圈的作用是找出與起點v0相連的點所形成的邊,那個邊的權值最小(最短路徑最短)) { MIN = dist[j] ; k = j ; } } vis[k] = 1 ; //改變相關點訪問狀態; int j ; for(j=0; j<n; j++) { if(vis[j]==0&&Map[k][j]<MAX) //如果這個點沒被訪問過。而且這個點j與點k之間存在邊的話(Map[k][j]<MAX意思是k,j之間有邊連線) { if(Map[k][j]+dist[k]<dist[j]) //這個點與k點的路徑+起點v0到k的最短路徑 < 起點v0到j的最短路徑 { dist[j] = Map[k][j] + dist[k] ; mon[j] = mon[j] + money[k][j] ; } else if(dist[k]+Map[k][j]==dist[j]&&mon[k]+money[k][j]<mon[j]) //路徑相同,錢不同 ; { mon[j] = mon[j] + Map[k][j] ; } } } } printf("%d %d\n",dist[vn],mon[vn]) ; } int main() { int t ; scanf("%d",&t) ; while(t--) { int v0, vn ; scanf("%d %d %d %d",&n,&m,&v0,&vn); int i, j ; for(i=0; i<n; i++) { for(j=0; j<n; j++) { if(i==j) Map[i][j] = 0 ; else Map[i][j] = MAX ; } } memset(vis,0,sizeof(vis)) ; int u, v, t, s ; for(i=0; i<m; i++) { scanf("%d %d %d %d",&u,&v,&t,&s); Map[u][v] = Map[v][u] = t ; money[u][v] = money[v][u] = s ; } Dijkstra(n,v0,vn) ; } return 0 ; }
————
餘生還請多多指教!