poj 次短路 dijkstra

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

对于某个点的次短路来说有两种可能,1、从一个点的最短路加上这两点之间的边权值。2、从一个点的次短路加上这两点之间的边权值。

回顾一下dijkstra,用到源点最短路径已经确定的点来更新其他的点的最短距离(也就是松弛操作),但是这样会发现每次都要遍历每个点来找到离源点最近的那一个(也就是已经能确定最短路径的一个),所以这里可以用一个优先队列来进行优化处理,将松弛操作中更新了最短路径的点加入队列中,这样每次从队列之中取出来的点就是已经确定最短路径的点。如果取得的点的最短距离比当前的取出的最短距离还小就跳过,不进行进行松弛操作。

那么在这基础上修改一下:对于每个顶点记录下最短路也要记录下次短路,在优先队列中加入次短路和最短路的,并利用优先队列取出最小的,进行松弛操作,此处的松弛操作要利用取出该点的信息(次短路或最短路)更新与他相邻的点的次短路和最短路。并且在将成功更新的点,连同他所被更新的路(有可能是次短路也有可能是最短路)一起加到队列中。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define M 10009
#define INF 0x3f3f3f3f
typedef pair<int,int> P;
typedef struct edge
{
    int to;
    int cost;
}edge;
vector<edge> G[M];
int n,m;
int dis[M];
int dis2[M];
priority_queue<P, vector<P> ,greater<P> > que;  //优先队列中存放最短路和次短路,因为求次短路可能是一个最短路加上一条边,也可能是一个次短路加上一条边。
void dijkstra()
{
    fill(dis,dis+n+1,INF);
    fill(dis2,dis2+n+1,INF);
    dis[1] = 0; //
    que.push(P(0,1));
    while(!que.empty())
    {
        P p = que.top();
        que.pop();
        int u = p.second;
        if(dis2[u] < p.first) continue;  //如果该点的次短距离已经比取出的这个距离小
        for(int i = 0;i < G[u].size();i++)
        {
            edge e = G[u][i];
            int d = p.first+e.cost; //不能跟最短路一样写成dis[u]+e.cost
            if(dis[e.to] > d)
            {
                swap(dis[e.to],d);  //交换两个
                que.push(P(dis[e.to],e.to));
            }
            if(dis2[e.to] > d && dis[e.to] < d) //这里比较巧妙 如果上面最短路已被更新,则交换了,那个d现在代表的是原来的最短路,这样的话之前的最短路就会变成次短路
            {
                dis2[e.to] = d;
                que.push(P(dis2[e.to],e.to));
            }
        }
    }
}
int main()
{
    while(scanf("%d %d",&n,&m)==2)
    {
        for(int i = 1;i <= n;i++)
            G[i].clear();
        for(int i = 0;i < m;i++)
        {
            int a ,b,value;
            scanf("%d %d %d",&a,&b,&value);
            edge e;
            e.to = b;
            e.cost = value;
            G[a].push_back(e); //无向图
            e.to = a;
            G[b].push_back(e);
        }
        dijkstra();
        printf("%d\n",dis2[n]);
    }
    return 0;
}<span style="color:#ff0000;">
</span>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值