解决k短路问题有很多思路,不过因为这道题目是次短路,所以我们考虑的可以简单一些。
先跑一遍spfa,记录下最短路的路径和在这条路上每个点的前驱,然后枚举最短路的路径删边,再重复跑最短路,取最小值。这样求得的就是次短路了。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<cmath>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=510;
const int maxm=500010;
int head[maxn],nnext[maxm],to[maxm];
double length[maxm],dis[maxn];
bool b[maxn];
double ans=INF;
int n,m,tot;
int x[maxn],y[maxn],pre[maxn];
double num(int i,int j)
{
int x1=x[i]-x[j];
int y1=y[i]-y[j];
return sqrt(x1*x1+y1*y1);
}
void add(int x,int y,double l)
{
tot++;
nnext[tot]=head[x];
head[x]=tot;
to[tot]=y;
length[tot]=l;
}
void spfa(int aa,int bb)
{
for(int i=1;i<=n;i++)
{
dis[i]=INF;
}
queue<int> q;
memset(b,false,sizeof(b));
q.push(1);
b[1]=true;
dis[1]=0;
while(!q.empty())
{
int now=q.front();
// cout<<dis[now]<<endl;
q.pop();
b[now]=false;
for(int i=head[now];i;i=nnext[i])
{
int y=to[i];
if(now==aa&&y==bb||now==bb&&y==aa) continue;
if(dis[y]>dis[now]+length[i])
{
dis[y]=dis[now]+length[i];
// cout<<y<<' '<<dis[y]<<endl;
if(aa==-1&&bb==-1) pre[y]=now;
if(!b[y])
{
b[y]=true;
q.push(y);
}
}
}
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d %d",&x[i],&y[i]);
}
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d %d",&x,&y);
double z=num(x,y);
add(x,y,z);
add(y,x,z);
}
spfa(-1,-1);
for(int i=n;pre[i];i=pre[i])
{
spfa(pre[i],i);
ans=min(ans,dis[n]);
}
if(ans==INF) cout<<"-1";
else printf("%.2lf",ans);
return 0;
}