信息学奥赛一本通 1342:【例4-1】最短路径问题
生活随笔
收集整理的這篇文章主要介紹了
信息学奥赛一本通 1342:【例4-1】最短路径问题
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
【題目鏈接】
ybt 1342:【例4-1】最短路徑問題
【題目考點】
1. 圖論 最短路徑
圖中有V個頂點E條邊,最短路徑算法時間復雜度:
- 樸素Dijkstra算法:O(V2)O(V^2)O(V2)
- Dijkstra堆優(yōu)化算法:O(ElogE)O(ElogE)O(ElogE)
- SPFA算法:一般情況下O(kE)O(kE)O(kE),k為頂點平均入隊次數(shù),最壞情況下O(VE)O(VE)O(VE)
- Floyd算法: O(V3)O(V^3)O(V3)
空間復雜度:
- 鄰接矩陣:O(V2)O(V^2)O(V2)
- 鄰接表:O(V+E)O(V+E)O(V+E)
【解題思路】
該題輸入各頂點坐標,以及每條邊是哪兩個點相連。那么需要我們手動計算兩點間距離,作為這條邊的權值。使用兩點間距離公式:(x1,x2)(x_1,x_2)(x1?,x2?)到(y1,y2)(y_1,y_2)(y1?,y2?)的距離
(x1?x2)2+(y1?y2)2\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}(x1??x2?)2+(y1??y2?)2?
建圖完成后,就是一個標準的求最短路徑問題。
注意:表示距離的數(shù)組,邊的權值,在該問題中都是double類型的。
double類型的數(shù)組dis,將元素都設為大約為1.08?10161.08*10^{16}1.08?1016的較大值,可以寫memset(dis, 0x43, sizeof(dis));
該題頂點數(shù)目為100,那么邊最多10000個。用哪種算法及存儲結構都可以。
該題頂點個數(shù)較少,可以使用Floyd算法及鄰接矩陣。本題主要展示最短路徑算法使用鄰接矩陣時的寫法。
如想看鄰接表的寫法,可以參考我在同一章節(jié)下其他題目的題解。
【題解代碼】
解法1:Floyd算法+鄰接矩陣
#include<bits/stdc++.h> using namespace std; #define N 105 struct Cord {int x, y; }; double edge[N][N]; int n, m, st, te;//st:起點 te:終點 double dis[N][N];//dis[i][j]:頂點i到頂點j的最短距離 Cord ver[N];//保存每個頂點的坐標 double getDis(Cord a, Cord b)//獲取點a到點b兩點間直線距離 {return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } void init() {int f, t;cin >> n;for(int i = 1; i <= n; ++i)cin >> ver[i].x >> ver[i].y;cin >> m;for(int i = 1; i <= m; ++i){cin >> f >> t;edge[f][t] = edge[t][f] = getDis(ver[f], ver[t]);//頂點f到頂點t的邊的權值為點f到點t的直線距離 }cin >> st >> te; } void floyd() {memset(dis, 0x43, sizeof(dis));//這樣可以使dis中每個元素的值大約為1.08e16,是一個較大值 for(int i = 1; i <= n; ++i)for(int j = 1; j <= n; ++j)if(edge[i][j] > 0)dis[i][j] = edge[i][j];for(int k = 1; k <= n; ++k)for(int i = 1; i <= n; ++i)for(int j = 1; j <= n; ++j)if(dis[i][j] > dis[i][k] + dis[k][j])dis[i][j] = dis[i][k] + dis[k][j]; } int main() {init();floyd();cout << fixed << setprecision(2) << dis[st][te];return 0; }解法2:樸素Dijkstra算法+鄰接矩陣
#include<bits/stdc++.h> using namespace std; #define N 105 struct Cord {int x, y; }; double edge[N][N]; int n, m, st, te;//st:起點 te:終點 double dis[N];//dis[i]:st到頂點i的最短距離 bool vis[N]; Cord ver[N];//保存每個頂點的坐標 double getDis(Cord a, Cord b)//獲取點a到點b兩點間直線距離 {return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } void init() {int f, t;cin >> n;for(int i = 1; i <= n; ++i)cin >> ver[i].x >> ver[i].y;cin >> m;for(int i = 1; i <= m; ++i){cin >> f >> t;edge[f][t] = edge[t][f] = getDis(ver[f], ver[t]);//頂點f到頂點t的邊的權值為點f到點t的直線距離 }cin >> st >> te; } void dijkstra() {memset(dis, 0x43, sizeof(dis));//這樣可以使dis中每個元素的值大約為1.08e16,是一個較大值dis[st] = 0; for(int k = 1; k <= n; ++k){int u = 0;for(int i = 1; i <= n; ++i)if(vis[i] == false && (u == 0 || dis[i] < dis[u]))u = i;vis[u] = true;for(int v = 1; v <= n; ++v){if(edge[u][v]){double w = edge[u][v];if(vis[v] == false && dis[v] > dis[u] + w)dis[v] = dis[u] + w;}}} } int main() {init();dijkstra();cout << fixed << setprecision(2) << dis[te];return 0; }解法3:SPFA算法+鄰接矩陣
#include<bits/stdc++.h> using namespace std; #define N 105 struct Cord {int x, y; }; double edge[N][N]; int n, m, st, te;//st:起點 te:終點 double dis[N];//dis[i]:st到頂點i的最短距離 bool vis[N]; //vis[i]:i是否在隊列內 Cord ver[N];//保存每個頂點的坐標 double getDis(Cord a, Cord b)//獲取點a到點b兩點間直線距離 {return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } void init() {int f, t;cin >> n;for(int i = 1; i <= n; ++i)cin >> ver[i].x >> ver[i].y;cin >> m;for(int i = 1; i <= m; ++i){cin >> f >> t;edge[f][t] = edge[t][f] = getDis(ver[f], ver[t]);//頂點f到頂點t的邊的權值為點f到點t的直線距離 }cin >> st >> te; } void spfa() {memset(dis, 0x43, sizeof(dis));//這樣可以使dis中每個元素的值大約為1.08e16,是一個較大值queue<int> que;dis[st] = 0; que.push(st);vis[st] = true;while(que.empty() == false){int u = que.front();que.pop();vis[u] = false;for(int v = 1; v <= n; ++v){if(edge[u][v]){double w = edge[u][v];if(dis[v] > dis[u] + w){dis[v] = dis[u] + w;if(vis[v] == false){vis[v] = true;que.push(v);} }}}} } int main() {init();spfa();cout << fixed << setprecision(2) << dis[te];return 0; }解法4:Dijkstra堆優(yōu)化算法+鄰接表
#include<bits/stdc++.h> using namespace std; #define N 105 struct Cord {int x, y; }; struct Edge {int t;double w;Edge(){}Edge(int a, double b):t(a),w(b){} }; struct Pair {int u;//u:頂點double d;//距離 Pair(){}Pair(int a, double b):u(a),d(b){}bool operator < (const Pair &b) const{return b.d < d;} }; vector<Edge> edge[N]; int n, m, st, te;//st:起點 te:終點 double dis[N];//dis[i]:st到頂點i的最短距離 bool vis[N]; //vis[i]:i是否在隊列內 Cord ver[N];//保存每個頂點的坐標 double getDis(Cord a, Cord b)//獲取點a到點b兩點間直線距離 {return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } void init() {int f, t;double w;cin >> n;for(int i = 1; i <= n; ++i)cin >> ver[i].x >> ver[i].y;cin >> m;for(int i = 1; i <= m; ++i){cin >> f >> t;w = getDis(ver[f], ver[t]); edge[f].push_back(Edge(t, w));edge[t].push_back(Edge(f, w)); }cin >> st >> te; } void dijkstra() {priority_queue<Pair> pq;memset(dis, 0x43, sizeof(dis));//這樣可以使dis中每個元素的值大約為1.08e16,是一個較大值dis[st] = 0;pq.push(Pair(st, 0));while(pq.empty() == false){int u = pq.top().u;pq.pop();if(vis[u])//如果頂點u已經訪問過,則跳過 continue;vis[u] = true;for(int i = 0; i < edge[u].size(); ++i) {int v = edge[u][i].t;double w = edge[u][i].w; if(vis[v] == false && dis[v] > dis[u] + w)//松弛{dis[v] = dis[u] + w;pq.push(Pair(v, dis[v]));}}} } int main() {init();dijkstra();cout << fixed << setprecision(2) << dis[te];return 0; }總結
以上是生活随笔為你收集整理的信息学奥赛一本通 1342:【例4-1】最短路径问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android中momery检测,And
- 下一篇: mysql 四叉树的应用_游戏算法(2)