POJ 3255 RoadBlocks(次短路+dijkstra變形)

題目

http://poj.org/problem?id=3255

題意:求從起點到終點的次短路。次短路是指比最短路長的路徑中,相對最短的那一條。

解題思路

《挑戰程序設計競賽》中的一道題。
引用別人的博文->圖論算法小結:次短路的求解

首先來回顧一下Dijkstra算法的原理:首先把所有結點的最短距離設置爲無窮大,然後令d[0]=0。接下來,每次都找到最短路已經確定的經典,更新從它出發的相鄰結點的最短距離。以後我們不再考慮最短距離已經確定了的結點。

以上就是Dijkstra算法的主要過程,需要注意的一點是我們不再考慮的是“最短距離已經確定了的結點”,不要錯誤地理解爲是更新過最短距離值的結點。因爲有些結點的最短路可能需要多次更新才能最終確定。那麼問題來了,如何知道哪些結點的最短距離是確定的呢?這裏我們利用了一點貪心的思想,每次都取出當前距離最短的那個結點,認爲它的最短路就是已經確定好的。可以證明這樣的做法是正確的。這也算爲什麼優化版本的DIjkstra算法用到了priority_queue的原因。

那麼回到主題,如何求解次短路呢?如果我們要求解起點s到終點t的次短路,那麼有兩種可能的情況:(1)起點s到某個頂點u的最短路+d(u,t)。(2)起點到某個頂點u的次短路+d(u,t)。因此,對於每個結點,我們記錄的不僅僅是最短距離,還有次短距離,接下來用類似於Dijkstra算法不斷更新這兩個距離即可求出次短路了。

解題思路

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;

struct edge
{
    int to, cost;
    edge(){}
    edge(int _to, int _cost) //構造邊的終點和權重
    {
        to = _to;
        cost = _cost;
    }
};
typedef pair<int, int> P;
const int maxn = 5005, INF = 1<<27;

int N, R;
vector<edge> G[maxn]; //G[0...n-1],G[i]存放從i出發的所有邊
int dist[maxn], dist2[maxn]; //dist存放最短距離,dist2存放次短路距離

void init() //初始化
{
    fill(dist, dist + maxn, INF);
    fill(dist2, dist2+ maxn, INF);
}

void dijkstra(int src)  //dijkstra算法變形——兼顧最短路和次短路
{
    init();
    priority_queue<P, vector<P>, greater<P> > q;
    dist[0] = 0; //標記源點的最短路爲0,但不標記次短路
    q.push(P(0,src));
    while(!q.empty())
    {
        P out = q.top(); q.pop();
        int pos = out.second, d = out.first;
        if (d > dist2[pos]) continue; //取出的比當前次短距離還長,也就比最短距離更長,跳過
        //鬆弛,從pos出發的每條邊鬆弛
        for (int i = 0; i < G[pos].size(); ++i)
        {
            edge &e = G[pos][i]; //pos到某個頂點的邊
            int d2 = d + e.cost; //源點通過pos到e.to的新距離
            if (d2 < dist[e.to]) //d2能直接更新最短路
            {
                swap(dist[e.to], d2); //替換下最短路
                q.push(P(dist[e.to], e.to));
            }
            //d2的可能性:1.不能替換最短路,但是可以直接替換次短路;2.之前最短路被替換下來的值可以更新次短路
            if (d2 > dist[e.to] && d2 < dist2[e.to])
            {
                dist2[e.to] = d2;
                q.push(P(dist2[e.to], e.to));
            }
        }
    }
}

int main()
{
    cin >> N >> R;
    int c1, c2, cos;
    for (int i = 0; i < R; ++i) //輸入每條路徑
    {
        cin >> c1 >> c2 >> cos;
        G[c1-1].push_back(edge(c2-1, cos));
        G[c2-1].push_back(edge(c1-1, cos));
    }
    dijkstra(0);
    cout << dist2[N-1] <<  endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章