[Algotithm] 最短路之旅
這可能是非常久以前的東西。
不過想想復習一下也是好的(其實是發現居然不會dijkstra了)。
一、通用原理
維護一個數組記錄所有點的最短路。
枚舉邊確認是否可以通過這條邊減小其它點的最短距離。
得出答案。
二、主流算法
A. Dijkstra
Dijkstra,荷蘭人。
Dijkstra要求提供兩個點集,分別用於存放不再修改的點與待修改的點(也就是是否找到最短路)
顯然第一個不再修改的點是起點,且其最短路為0。
那麽,首先找到已知的最短路徑最短的點(想象一個凸多邊形,哪裏離中心最近就哪裏進行擴張)。
然後這個點扔進不再修改的點集(記為A)。
然後枚舉其邊以更新其它點的最短路。
顯然,這種方式將持續n次,因為每次都必然扔且只扔一個點進去點集A。
然後查找的過程又是n次。
最後枚舉邊如果用鄰接矩陣的話也是n次,如果用鄰接表的話可以E(E是邊數)。
PS:我並不是說準確次數啊,n-1 接近 n 所以我直接說 n QwQ
那麽樸素dijkstra的復雜度就是O(n^2+nE),近似看作O(n^2)。
堆優化:
想要減小時間復雜度,第一個要優化的就是查找枚舉基點的過程,畢竟每次都O(n)。
這段部分就其根本是要找到可修改的最短距離。
那麽我們可以用一個堆(或優先隊列)代替原來的樸素隊列使得我們要找的最小dis每次就在堆頂。
題目:
單源最短路:https://www.luogu.org/problem/show?pid=3371
這道題數據還算不錯。
註意:數據大小需要註意。
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 #define maxn_P 10101 5 #define maxn_E 505050 6 #define推薦不看INF 2147483647 7 using namespace std; 8 typedef pair<int,int> node; 9 10 struct edge{ 11 int from,v,len; 12 }e[maxn_E]; 13 14 int first[maxn_P],tot,dis[maxn_P],n,m,s,a,b,c; 15 bool book[maxn_P]; 16 17 void insert(int u,int v,int len){ 18 tot++; 19 e[tot].from = first[u]; 20 e[tot].v = v; 21 e[tot].len = len; 22 first[u] = tot; 23 } 24 25 void dijkstra(){ 26 for(int i = 1;i <= n;i++) dis[i] = INF; 27 28 priority_queue<node,vector<node>,greater<node> > q; 29 30 dis[s] = 0; 31 32 q.push(make_pair(dis[s],s)); 33 34 while(!q.empty()){ 35 node tmp = q.top(); 36 q.pop(); 37 int p = tmp.second; 38 39 if(!book[p]){ 40 book[p] = true; 41 for(int i = first[p];i;i = e[i].from){ 42 if(dis[e[i].v] > dis[p]+e[i].len){ 43 dis[e[i].v] = dis[p]+e[i].len; 44 q.push(make_pair(dis[e[i].v],e[i].v)); 45 } 46 } 47 } 48 } 49 } 50 51 int main(){ 52 scanf("%d%d%d",&n,&m,&s); 53 54 for(int i = 0;i < m;i++){ 55 scanf("%d%d%d",&a,&b,&c); 56 insert(a,b,c); 57 } 58 59 dijkstra(); 60 61 for(int i = 1;i <= n;i++){ 62 printf("%d ",dis[i]); 63 } 64 65 return 0; 66 }
To be filled
[Algotithm] 最短路之旅