PAT甲级1131 Subway Map (30分):[C++题解]堆优化dijkstra、单源最短路、地铁地图、巧妙地建图套dijkstra模板!!
文章目錄
- 題目分析
- 題目鏈接
題目分析
原題:
來源:acwing
分析:
建圖:所有能走到的點之間建立一條邊,比如下面一條地鐵線路有4站,它們是相通的,兩兩之間建一條邊,邊權是經過的站點數。
下面考慮一下使用哪種最短路算法。
每條線路最多100個點,如上這樣建圖,最多的邊數為:C1002<5000<10000C_{100}^2 < 5000 < 10000C1002?<5000<10000條邊;最多有100條路線,最多10000個點,最多建立 10000 × 100 = 1e6條邊,即100萬條邊。
使用樸素的dijkstra算法會超時O(n2)=100002=108超時O(n^2) = 10000^2=10^8超時O(n2)=100002=108超時, 需要使用堆優化版本的dijkstra()算法O(m×logn)=1e6×log10000=4e6不會超時O(m\times logn) =1e6 \times log10000 = 4e6不會超時O(m×logn)=1e6×log10000=4e6不會超時
限制1s的話,運算1e8次差不多;現在限制是0.4s,差不多運算 5e7次才不超時。
看題意:第一點,首先輸出最少需要停靠的站點數量,這就是在我們的建圖中最短路(每條邊有權重,權重等于結點之間的站點數);第二點,如果最快線路不唯一,則輸出換乘次數最少的線路,換乘次數最少,在我們的圖中等價于邊數最少,因為同一條路線上的點只有一條邊,邊數越多,表示經過的線路越多。
綜上:最短路取決于邊權大小;換乘少取決于邊數少。
建圖如下:下圖有兩條地鐵線路,分別有4個站點和5個站點,并且有1個換乘站,所以下面的幾個點都是連通的,可以通過換乘到達。我們的建圖原則是:在一條線路上的任意兩站之間建一條邊,邊權為兩者之間的站點數量。
堆優化版的dijkstra算法模板請移步最短路[Dijkstra和堆優化的Dijkstra][Bellman-Ford和SPFA][Floyd最短路](更新中)
ac代碼
#include<bits/stdc++.h> using namespace std; const int N =10010 , M =1e6+10; typedef pair<int,int> PII; # define x first #define y secondint n , h[N],e[M],ne[M],w[M],idx; int line[M];//每條邊屬于幾號線 int stops[N];//站點 int dist[N];// int cnt[N]; //記錄經過的邊數;換成少===經過的邊數少 bool st[N]; int pre[N]; string info[N];//記錄地鐵線路信息/* 鄰接表建邊:建立a到b的邊 a和b是站點 c是權值,表示中間隔了幾站 id是線路號line */void add(int a ,int b, int c, int id){e[idx] =b,w[idx] =c,line[idx] =id, ne[idx] = h[a] ,h[a] =idx ++; }//4位站牌號,不足補上 string get_number(int x){string res = to_string(x);while(res.size() <4) res = '0' + res;return res;}void dijkstra(int start, int end){memset(dist, 0x3f, sizeof dist);memset(cnt, 0 ,sizeof cnt);memset(st, 0 ,sizeof st);dist[start] = 0 ,cnt[start] =0;priority_queue<PII, vector<PII> ,greater<PII>> heap;//小根堆heap.push({0,start}); //加入起點{距離,編號}while(heap.size()){auto t = heap.top();heap.pop();int ver =t.y; //節點編號if(ver == end) break;if(st[ver]) continue;st[ver] =true;for(int i=h[ver]; i!= -1; i = ne[i]){int j = e[i];//距離更短,更新if(dist[j] > dist[ver] + w[i]){dist[j] =dist[ver] +w[i];cnt[j] =cnt[ver] +1; //走過的邊數pre[j] = ver;info[j] ="Take Line#"+to_string(line[i])+ " from "+ get_number(ver) +" to "+ get_number(j) +".";heap.push({dist[j] ,j});}//距離相同,看看else if( dist[j] == dist[ver] +w[i]){if(cnt[j] > cnt[ver] + 1){cnt[j] =cnt[ver] +1;pre[j] = ver;info[j] ="Take Line#"+to_string(line[i])+ " from "+ get_number(ver) +" to "+ get_number(j) +".";heap.push({dist[j],j});}}}}cout<< dist[end]<<endl;vector<string > path;//倒序存入pathfor(int i = end; i != start; i =pre[i]) path.push_back(info[i]);for(int i =path.size()-1; i>=0 ;i--) cout<< path[i ] <<endl; }int main() {cin >> n;memset(h ,-1 ,sizeof h); //鄰接表初始化for(int i =1; i<= n; i++){ //n條線路int m;//站點cin >> m;for(int i = 0; i< m; i++) cin >> stops[i];//同一條線路上的站點,因為都是連通的,兩兩之間建邊for(int j = 0; j< m; j++){for(int k =0; k< j; k++){int length;//如果不是環路if(stops[0] !=stops[m-1]) length = j - k;//如果是環路,取兩邊短的else length = min(j - k , m-1 - j +k);//建邊的時候把長度也建好了,等于之間走了幾站:lengthadd(stops[j],stops[k],length, i); add(stops[k],stops[j], length ,i);}}}int m;cin >> m;while(m--){int start ,end;cin >> start >> end;dijkstra(start, end);}}題目鏈接
PAT甲級1131 Subway Map (30分)
https://www.acwing.com/problem/content/1626/
總結
以上是生活随笔為你收集整理的PAT甲级1131 Subway Map (30分):[C++题解]堆优化dijkstra、单源最短路、地铁地图、巧妙地建图套dijkstra模板!!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小白也能看懂的git入门实操[狂神聊gi
- 下一篇: PAT甲级1134 Vertex Cov