【dijkstra優化/次短路徑】POJ3255-Roadblocks

【題目大意】ios

給出一張無向圖,求出從源點到終點的次短邊。數組

【思路】優化

先來談談Dijkstra的優化。對於每次尋找到當前爲訪問過的點中距離最短的那一個,運用優先隊列進行優化,避免所有掃描,每更新一個點的最短距離就加入優先隊列。有人會問,一個點若是已經處理完成了,那它還留在隊列中怎麼辦?咱們放入隊列時將一個點那時的頂點編號和最短距離進行打包,若是取出該點時,它當前的最短距離小於該點標記的最短距離,說明該點已經取到最短距離,不進行操做。或者直接用一個vis數組來記錄某一個點是否已經取到最短距離;其次的優化是用鄰接表存儲與每個點相連的全部邊,方便處理。spa

這道題的作法和最短路徑基本一致,惟一的不一樣點在於,在求出最短路徑的狀況下必需要保留下次短路徑。對於Dijkstra判斷中取出的每個點,若是到它的最短距離大於當前該點的次短距離,則當前該點已經取到最短距離和次短距離,不進行操做,不然進行兩次判斷:若是小於最短邊,則賦給最短變,並將最短邊賦給次短邊;或者若是大於最短變且小於次短邊,則賦給次短邊。兩次完成以後均要加入隊列。要注意幾點:code

(1)因爲是一張無向圖,讀入的時候必須正向、逆向分爲兩條邊存儲,因此實際有向邊的數量爲r的兩倍,數組絕對不能開小!我就由於這個錯拿了90分,還檢查了三個小時後找到測試數據才意識到的...blog

(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 }
相關文章
相關標籤/搜索