次短路
次短路
介绍
次短路其实没什么好说的,是一个非常简单的算法,和最短路几乎一样,但是如果没有想过那考试的时候还是可能码错
具体实现就是在 Dijkstra 基础上做一些改动,原本的 Dijkstra 是在最短路可以被更新时直接更新,现在加入次短路后就需要分情况讨论
如果堆顶信息比当前节点的次短路还要长就没有任何贡献直接扔掉
如果堆顶信息比当前节点的最短路还要短那么就把次短路更新为原本的最短路,再把堆顶信息作为新的最短路并且把节点加入堆
如果堆顶信息比当前节点的最短路长但是比次短路短,那就把次短路更新为堆顶信息,由于次短路有可能也能更新后面的节点信息,所以也需要把这个节点加入堆中
不难发现,由于我们只需要最短路和次短路,所以这个节点第一次从堆中被取出时它的最短路就确定了(就像普通的 Dijkstra 一样),第二次从堆中被取出时它的次短路也就确定了
Code
#include<bits/stdc++.h>
#define in read()
using namespace std;
#define getchar() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?EOF:*S++)
char B[1<<15],*S=B,*T=B;
inline int read()
{
char c=getchar();
int x=0;
while(c<48)c=getchar();
while(c>47)x=(x*10)+(c^48),c=getchar();
return x;
}
inline void mwrite(int a)
{
if(a>9)mwrite(a/10);
putchar((a%10)|48);
}
inline void write(int a,char c)
{
mwrite(a);
putchar(c);
}
#define MAXN 5003
#define MAXM 200005
#define INF 2100000000
int n,m;
int dis[MAXN][3];//dis[i][0]表示1到节点i的最短路长度,dis[i][1]表示1到节点i的次短路长度
struct Node
{
int id,dis;
bool operator <(const Node& x)const
{
return dis>x.dis;
}
Node(int Id=0,int Dis=0):id(Id),dis(Dis){}
};
int head[MAXN],nxt[MAXM],to[MAXM],w[MAXM],cnt;
inline void create(int ff,int tt,int ww){nxt[++cnt]=head[ff],head[ff]=cnt,to[cnt]=tt,w[cnt]=ww;}
inline void dij()
{
for(int i=1;i<=n;++i) dis[i][0]=dis[i][1]=INF;
dis[1][0]=0;
priority_queue<Node> q;
q.push((Node){1,0});
int pos,d;
while(!q.empty())
{
pos=q.top().id,d=q.top().dis,q.pop();
if(d>dis[pos][1]) continue;//如果即将更新的信息比节点的次短路更大就直接舍弃
for(int i=head[pos];i;i=nxt[i])
{
if(dis[to[i]][0]>d+w[i])//如果即将更新的信息比节点的最短路更小就让最短路替换次短路,让新信息更新最短路
{
dis[to[i]][1]=dis[to[i]][0];
q.push((Node){to[i],dis[to[i]][0]=d+w[i]});
}
if(dis[to[i]][0]<d+w[i]&&dis[to[i]][1]>d+w[i])//如果即将更新的信息比节点的最短路大但是比次短路小就让新信息更新次短路
q.push((Node){to[i],dis[to[i]][1]=d+w[i]});//即使仅更新了次短路也应该加入优先队列,因为可能更新其他节点的次短路
}
}
}
signed main()
{
n=in,m=in;
for(int i=1,t1,t2,t3;i<=m;++i)
{
t1=in,t2=in,t3=in;
create(t1,t2,t3);
create(t2,t1,t3);
}
dij();
write(dis[n][1],'\n');
return 0;
}
该文为本人原创,转载请注明出处