感觉此题可作为严格次短路的模板,因此来写一写
Description
给定 (n) 个点,(r) 条双向道路,求从 (1) 号点到 (n) 号点的严格次短路
Solution
维护两个变量,最短路和次短路
(Dis[i][0]) 表示从 (1) 号点到 (i) 号点的最短路,(Dis[i][1]) 表示从 (1) 号点到 (i) 号点的次短路
然后考虑什么情况下会对最短路或次短路的更新造成影响
设 (fr) 是当前节点,(to) 是当前节点连出去的某个节点
当 (Dis[to][0]>Dis[fr][0]+e[i].dis) 时,表明当前点 (to) 的最短路不再是最短的,就把当前最短路更新成次短路,然后再更新最短路
当 (Dis[to][1]>Dis[fr][1]+e[i].dis) 时,发现当前点 (to) 的次短路可以更短,但对最短路无影响,就只更新次短路
当 (Dis[to][1]>Dis[fr][0]+e[i].dis) 并且 (Dis[to][0]<Dis[fr][0]+e[i].dis) 时,表明当前点 (to) 的次短路可以更新,而最短路已经是最优,则只更新次短路
综上,每次按上述方法更新每条边,就可以求出到每个点的严格次短路
最后答案就是 (Dis[n][1])
Code
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 5010
#define LL long long
#define uLL unsigned long long
using namespace std;
queue<int> q;
int n,r,tot,head[maxn];
int Dis[maxn][3],vis[maxn];
struct edge{int fr,to,dis,nxt;}e[maxn<<1];
inline int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
inline void add(int fr,int to,int dis){
e[++tot].fr=fr;e[tot].to=to;
e[tot].dis=dis;e[tot].nxt=head[fr];
head[fr]=tot;
}
inline void SPFA(){
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to,dis=e[i].dis;
if(Dis[to][0]>Dis[u][0]+dis){
Dis[to][1]=Dis[to][0];
Dis[to][0]=Dis[u][0]+dis;
if(!vis[to]) vis[to]=1,q.push(to);
}
if(Dis[to][1]>Dis[u][1]+dis){
Dis[to][1]=Dis[u][1]+dis;
if(!vis[to]) vis[to]=1,q.push(to);
}
if(Dis[to][1]>Dis[u][0]+dis&&Dis[to][0]<Dis[u][0]+dis){
Dis[to][1]=Dis[u][0]+dis;
if(!vis[to]) vis[to]=1,q.push(to);
}
}
}
}
int main(){
n=read();r=read();
memset(Dis,63,sizeof Dis);
q.push(1);vis[1]=1;Dis[1][0]=0;
for(int i=1,fr,to,dis;i<=r;i++){
fr=read();to=read();dis=read();
add(fr,to,dis);add(to,fr,dis);
}
SPFA();printf("%d",Dis[n][1]);
return 0;
}