次短路有两种计算方法。
方法一、更新最短路时同步更新次短路
对于一条端点为u、v的边,点v的次短路,要么是点u的次短路加边权,要么是点u的最短路加边权。
设两个数组,dist1存储最短路,dist2存储次短路,则存在下面的等式:
dist2[v]=min{dist2[u]+wdist1[u]+wdist1[u]+w>dist1[v] dist2[v]=min\left\{
\begin{array}{rcl}
dist2[u]+w \\
dist1[u]+w&&{dist1[u]+w>dist1[v]} \\
\end{array}
\right.
dist2[v]=min{dist2[u]+wdist1[u]+wdist1[u]+w>dist1[v]
在更新最短路的同时更新次短路即可。
代码
void spfa()
{
queue<int> q;
memset(dist,INF,sizeof(dist));
memset(dist2,INF,sizeof(dist2));
dist[1]=0;
book[1]=true;
q.push(1);
while(q.size())
{
int u=q.front();q.pop();
book[u]=false;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i].first,w=G[u][i].second;
if(dist[v]>dist[u]+w)//更新最短路
{
dist2[v]=dist[v]; //同时更新次短路
dist[v]=dist[u]+w;
if(!book[v])
{
q.push(v);book[v]=true;
}
}
if(dist2[v]>dist2[u]+w)
{
dist2[v]=dist2[u]+w;
if(!book[v])
{
q.push(v);book[v]=true;
}
}
if(dist2[v]>dist[u]+w && dist[u]+w>dist[v])
{
dist2[v]=dist[u]+w;
if(!book[v])
{
q.push(v);book[v]=true;
}
}
}
}
}
二、计算出最短路后再枚举
对于无向图,先从1跑一遍最短路,存储在dist1,再从n跑一遍最短路,存储在dist2,对于每一条边,计算dist1[u]+dist2[v]+w,从里面找出次短路。
等式如下:
ans=min(ans,dist1[u]+dist2[v]+w) 满足:(dist1[u]+dist2[v]+w)>dist1[n]ans=\min(ans,dist1[u]+dist2[v]+w) \text{ 满足:(dist1[u]+dist2[v]+w)>dist1[n]}ans=min(ans,dist1[u]+dist2[v]+w) 满足:(dist1[u]+dist2[v]+w)>dist1[n]
代码
图的存储
//建图
typedef pair<int,int> P;
vector<P> G[N];
for(int i=1,x,y,z;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
G[x].push_back(make_pair(y,z));
G[y].push_back(make_pair(x,z));
}
跑完最短路后,求次短路。
//dist1和dist2分别是起点为1和n的最短路径
int ans=0x3FFFFFFF;
for(int i=1;i<=n;i++)
for(int j=0;j<G[i].size();j++)
{
int w=G[i][j].second,v=G[i][j].first;
if(dist[i]+dist2[v]+w>dist[n])
ans=min(ans,dist[i]+dist2[v]+w);
}