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>