次短路
次短路顾名思义,第二短路。
最短路做法:
有两种可能,一是在最短路上重复走最短边,另一个是至少换另一条边到路径里。
正反跑两遍最短路,然后枚举不属于最短路的每条边( \(a\) , \(b\) ) , 找 \(dis[1 \Rightarrow a][0]+val[a][b]+dis[b\Rightarrow n][1]\)。
如果 $dis[1 \Rightarrow a][0]+val[a][b]+dis[1\Rightarrow b]= $ 最短路,该边即为最短路上的边,记录最小值最后比较两种可能的最小值。
const int N=1e6+10;
int n,m,x,y,z,cnt,mn,ans=inf,head[N],dis[N][3],vis[N];
struct node{
int u,v,w,nxt;
}a[N];
void add(int u,int v,int w){
a[++cnt]=(node){u,v,w,head[u]};
head[u]=cnt;
}
priority_queue<int, vector<pair<int,int> > , greater<pair<int,int> > > q;
void dij(int x,int l){
cl(vis,0);
dis[x][l]=0;
q.push(make_pair(0,x));
while(!q.empty()){
int now=q.top().se;
q.pop();
if(vis[now]) continue;
vis[now]=1;
for(int i=head[now];i;i=a[i].nxt){
int v=a[i].v;
if(dis[v][l]>dis[now][l]+a[i].w){
dis[v][l]=dis[now][l]+a[i].w;
if(!vis[v]){
q.push(make_pair(dis[v][l],v));
}
}
}
}
}
signed main(){
n=read();m=read();
rep(i,1,m){
x=read();y=read();z=read();
if(x==y) continue;
add(x,y,z);
add(y,x,z);
}
cl(dis,inf);
dij(1,0);dij(n,1);
mn=dis[n][0];
for(int i=1;i<=cnt;i+=2){
int u=a[i].u,v=a[i].v,w=a[i].w;
if(dis[u][0]+dis[v][1]>dis[u][1]+dis[v][0]) swap(u,v);
if(dis[u][0]+dis[v][1]+w==mn) continue;
ans=Min(ans,dis[u][0]+dis[v][1]+w);
}
int mnb=inf;
for(int i=1;i<=cnt;i+=2){
int u=a[i].u,v=a[i].v,w=a[i].w;
if(dis[u][0]+dis[v][1]>dis[u][1]+dis[v][0]) swap(u,v);
if(dis[u][0]+w+dis[v][1]==mn) mnb=Min(w,mnb);
}
cout<<Min(ans,mn+mnb*2);
return 0;
}
还有一种 \(A\) * 算法(待补)。

浙公网安备 33010602011771号