题解:求次短路,先spfa跑一遍最短路,再依次删去最短路中的边找次短路,同时更新最短路顶点里最短的邻边,两种情况中取最小值。
#include<iostream>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const ll inf=1e15+10;
const int maxn=1e5+10;
struct edge{
int u,v;ll w;
}e[maxn];
int t,n,m,pre[maxn];
bool vis[maxn],flag[maxn];
ll sp,mn,ans,dis[maxn];
vector<int> p[maxn];
queue<int> q;
ll spfa(){
for(int i=2;i<=n;i++) vis[i]=0,dis[i]=inf;
q.push(1);
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
for(int i=0;i<p[u].size();i++){
int v;
if(u==e[p[u][i]].u) v=e[p[u][i]].v;
else v=e[p[u][i]].u;
if(dis[v]>dis[u]+e[p[u][i]].w){
dis[v]=dis[u]+e[p[u][i]].w;
pre[v]=p[u][i];
if(!vis[v]) q.push(v),vis[v]=1;
}
}
}
return dis[n];
}
ll spfasec(){
for(int i=2;i<=n;i++) vis[i]=0,dis[i]=inf;
q.push(1);
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
for(int i=0;i<p[u].size();i++){
if(flag[p[u][i]]) continue;
int v;
if(u==e[p[u][i]].u) v=e[p[u][i]].v;
else v=e[p[u][i]].u;
if(dis[v]>dis[u]+e[p[u][i]].w){
dis[v]=dis[u]+e[p[u][i]].w;
if(!vis[v]) q.push(v),vis[v]=1;
}
}
}
return dis[n];
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) flag[i]=0,p[i].clear();
for(int i=0;i<m;i++){
scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w);
p[e[i].u].push_back(i);
p[e[i].v].push_back(i);
}
sp=spfa();
//printf("%lld\n",mn);
int u=n;ans=mn=inf;
for(int i=0;i<p[1].size();i++) mn=min(mn,e[p[1][i]].w);
while(u!=1){
flag[pre[u]]=1;
ans=min(ans,spfasec());
if(u!=n)
for(int i=0;i<p[u].size();i++) mn=min(mn,e[p[u][i]].w);
flag[pre[u]]=0;
if(u!=e[pre[u]].u) u=e[pre[u]].u;
else u=e[pre[u]].v;
}
//printf("%lld\n",ans);
printf("%lld\n",min(ans,mn*2+sp));
}
}