Dijkstra应用之次短路

来源:互联网 发布:郑州软件 编辑:程序博客网 时间:2024/06/05 04:26

        我们都知道Dijkstra算法是求解单源最短路的算法。那么现在我们问题不在是最短路了,而是次短路(第二短的路径)。我们现在还能使用DIjkstra算法吗?当然了,你看到这篇博客的名字就知道了。其实一开始我也没想到用Dijkstra来求解次短路问题,在看《挑战程序设计竞赛》的时候看到这种解法,感觉特别神奇,于是来和大家分享分享。

        那么我们现在先回忆下Dijkstra是怎么求解最短路问题的。Dijkstra的思想是根据确定最短路的顶点来计算尚未确定顶点的最短路,这句话是什么意思呢?比如在一幅无向图中,s为源点,v1为已经确定最短路的顶点,v2,v3为尚未确定的顶点。那么我们使用v1的最短距离加上v1->v2或v3的距离,来更新v2,v3到源点s的距离。显然这么一直更新下去,那么最终s到v2,v3的距离就是最短距离(详情请参考:Here)。

        如果dist[v]表示s->v的最短距离,dist2[v]表示s->v的次短距离,d为s->v的第k短距离(k>1)。那么一定满足这样一个关系,dist[v] < dist2[v] <= k。看到这个等式的时候我们可以发现,如果dist2[v] > d2 > dist[v],显然这时候我们需要将dist2[v]更新为d2。那么我们只要找到不满足dist[v] < dist2[v] <= k这个的式子的dist2[v],那么我们就更新他。一直更新到所以式子都满足这个式子,那么dist2[v]就为源点s->v的次短路。到此我们已经推出了求解次短路的方法。

        老规矩,来到水题练练手,POJ 3255 Roadblocks。解题代码如下:

#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#define MAXN (5000 + 10)#define INF (5000*5000*2)using namespace std;struct edge{    int to, cost;    edge(int tv = 0, int tc = 0):        to(tv), cost(tc){}};typedef pair<int ,int> P;int N, R;vector<edge> graph[MAXN];int dist[MAXN];     //最短距离int dist2[MAXN];    //次短距离void solve(){    fill(dist, dist+N, INF);    fill(dist2, dist2+N, INF);    //从小到大的优先队列    //使用pair而不用edge结构体    //是因为这样我们不需要重载运算符    //pair是以first为主关键字进行排序    priority_queue<P, vector<P>, greater<P> > Q;    //初始化源点信息    dist[0] = 0;    Q.push(P(0, 0));    //同时求解最短路和次短路    while(!Q.empty()){        P p = Q.top(); Q.pop();        //first为s->to的距离,second为edge结构体的to        int v = p.second, d = p.first;        //当取出的值不是当前最短距离或次短距离,就舍弃他        if(dist2[v] < d) continue;        for(unsigned i = 0; i < graph[v].size(); i++){            edge &e = graph[v][i];            int d2 = d + e.cost;            if(dist[e.to] > d2){                swap(dist[e.to], d2);                Q.push(P(dist[e.to], e.to));            }            if(dist2[e.to] > d2 && dist[v] < d2){                dist2[e.to] = d2;                Q.push(P(dist2[e.to], e.to));            }        }    }    printf("%d\n", dist2[N-1]);}int main(){    int A, B, D;    scanf("%d%d", &N, &R);    for(int i = 0; i < R; i++){        scanf("%d%d%d", &A, &B, &D);        graph[A-1].push_back(edge(B-1, D));        graph[B-1].push_back(edge(A-1, D));    }    solve();    return 0;}




1 0
原创粉丝点击