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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章