【題目大意】
給出一張無向圖,求出從源點到終點的次短邊。
【思路】
先來談談Dijkstra的優化。對於每次尋找到當前為訪問過的點中距離最短的那一個,運用優先隊列進行優化,避免全部掃描,每更新一個點的最短距離就加入優先隊列。有人會問,一個點如果已經處理完成了,那它還留在隊列中怎么辦?我們放入隊列時將一個點那時的頂點編號和最短距離進行打包,如果取出該點時,它當前的最短距離小於該點標記的最短距離,說明該點已經取到最短距離,不進行操作。或者直接用一個vis數組來記錄某一個點是否已經取到最短距離;其次的優化是用鄰接表存儲與每一個點相連的所有邊,方便處理。
這道題的做法和最短路徑基本一致,唯一的不同點在於,在求出最短路徑的情況下必須要保留下次短路徑。對於Dijkstra判斷中取出的每一個點,如果到它的最短距離大於當前該點的次短距離,則當前該點已經取到最短距離和次短距離,不進行操作,否則進行兩次判斷:如果小於最短邊,則賦給最短變,並將最短邊賦給次短邊;或者如果大於最短變且小於次短邊,則賦給次短邊。兩次完成之后均要加入隊列。要注意幾點:
(1)由於是一張無向圖,讀入的時候必須正向、逆向分為兩條邊存儲,所以實際有向邊的數量為r的兩倍,數組絕對不能開小!我就因為這個錯拿了90分,還檢查了三個小時后找到測試數據才意識到的...
(2)初始化時,源點的短邊初始化為0,源點的次短邊必須初始化為INF,而不是0。比如下面這組數據:
4 2 1 2 100 2 4 200
答案應該是500,然而如果初始化為0則答案會輸出700。因為500的結果是又1到2,在從2返回1,再到2,再到4,100+100+100+200=500得到的;如果次短邊初始化為0,則次短路徑不再返回源點,而是在2與4之間折返,會偏大。
(3)53行絕對不能直接賦值,而是要swap!因為最短邊被修改后,它的值是要留給次短邊的。
2015.09.06溫習時候的補充
(1)要注意if (head.len>secondis[head.num]) continue;的位置!我兩次寫的時候都把它放在了while(k!=-1)里面然后判斷(d>secondis[v[k]])這是不對的!因為如果這個時候continue,k的值就無法改變,會導致死循環。
(2)要注意優先隊列默認是大頂堆,struct里面設置的時候前后大於小於號必須要相反才能設置成小頂堆!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<cstdlib> 6 using namespace std; 7 const int INF=0x7fffffff; 8 const int MAXN=100000+10; 9 struct Rec 10 { 11 int num,len; 12 bool operator < (const Rec &a) const 13 { 14 return len>a.len; 15 /*優先隊列強制設為以len為關鍵詞的小頂堆*/ 16 } 17 }; 18 int u[MAXN*2],v[MAXN*2],w[MAXN*2]; 19 /*依次表示每條道路的起點、終點和長度*/ 20 int dis[MAXN/2],secondis[MAXN/2]; 21 /*記錄通往每一個路口的最短和次短距離*/ 22 int first[MAXN/2],next[MAXN*2]; 23 int n,r; 24 25 void dijkstra() 26 { 27 priority_queue<Rec> que; 28 29 for (int i=1;i<n;i++) 30 { 31 dis[i]=INF; 32 secondis[i]=INF; 33 } 34 dis[0]=0; 35 secondis[0]=INF; 36 37 Rec temp; 38 temp.len=0;temp.num=0; 39 que.push(temp); 40 41 while (!que.empty()) 42 { 43 Rec head=que.top(); 44 que.pop(); 45 if (head.len>secondis[head.num]) continue; 46 47 int k=first[head.num]; 48 while (k!=-1) 49 { 50 int d=head.len+w[k]; 51 if (dis[v[k]]>d) 52 { 53 swap(dis[v[k]],d); 54 temp.len=dis[v[k]];temp.num=v[k]; 55 que.push(temp); 56 } 57 if (dis[v[k]]<d && secondis[v[k]]>d) 58 { 59 secondis[v[k]]=d; 60 temp.len=secondis[v[k]];temp.num=v[k]; 61 que.push(temp); 62 } 63 k=next[k]; 64 } 65 } 66 } 67 68 int main() 69 { 70 scanf("%d%d",&n,&r); 71 memset(first,-1,sizeof(first)); 72 for (int i=0;i<r;i++) 73 { 74 scanf("%d%d%d",&u[i],&v[i],&w[i]); 75 u[i]--; 76 v[i]--; 77 next[i]=first[u[i]]; 78 first[u[i]]=i; 79 80 v[i+r]=u[i]; 81 u[i+r]=v[i]; 82 w[i+r]=w[i]; 83 next[i+r]=first[u[i+r]]; 84 first[u[i+r]]=i+r; 85 } 86 dijkstra(); 87 cout<<secondis[n-1]<<endl; 88 return 0; 89 }
