题干
思路
这道题讲了这么多,其实就是要求节点1到节点n次短路。目标明确又简短,但怎么求这个次短路?
这一题实则还是运用最短路算法——次短路就是次于最短路的路径方案。所以,对于图,令其最短路径边集
,次短路径边集为
;当
时,
的最短路径边集
。
那么,当我们找出原图的所有最短路径并“删除”,再跑一边最短路就可以找到次短路了——但怎么“删边”呢?其实并不需要删边这么麻烦,我们只需要找到最短路径边集后,跳过最短路径上相邻的两个点就好了。代码如下:
for(int i=n;i!=1;i=frt[i])//frt:用于记录最短路径,存点的前缀
{
dijkstra(1,frt[i],i);//仍然从1开始,并跳过最短路径上的边(frt[i],i),避免题干中的“重复”
ans=min(ans,dis[n]);//记录答案,取最小值
}
最短路的实现还是用Dijkstra吧,spfa就算了。代码如下:
void dijkstra(ll s,ll uu,ll vv)//dijkstra的板子
//这里引入两个参数(uu,vv)
//如果是(-1,-1)代表是计算原图的最短路
//否则就是计算次短路时要跳过的边(frt[i],i)
{
for(int i=1;i<=n;i++)
dis[i]=inf,vis[i]=0;
dis[s]=0;
q.push((node){0,s});
while(!q.empty())
{
node tmp=q.top();
q.pop();
ll x=tmp.pos;
dd d=tmp.dis;
if(vis[x])continue;
vis[x]=1;
for(int i=head[x];i;i=e[i].next)
{
ll y=e[i].to;
if((x==uu&&y==vv)||(x==vv&&y==uu))continue;//跳过要删除的边
if(dis[y]>dis[x]/*d*/+e[i].w)
{
dis[y]=dis[x]/*d*/+e[i].w;
if(uu==-1&&vv==-1)frt[y]=x;//用前缀形式存原图最短路
q.push((node){dis[y],y});
}
}
}
}
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define dd double
const ll z=3e6+9,mod=100003;
const dd inf=2e9;
dd x,y,dis[z],ans;
ll n,m,u,v,frt[z];
bool vis[z];
struct point
{
dd x,y;
}p[z];
struct edge
{
ll to,next;
dd w;
}e[z*2];
ll head[z*2],idx;
void addedge(ll u,ll v,dd w)
{
idx++;
e[idx].to=v;
e[idx].next=head[u];
e[idx].w=w;
head[u]=idx;
}
struct node
{
dd dis;
ll pos;
bool operator<(const node &x)const
{
return x.dis<dis;
}
};
priority_queue<node>q;
void dijkstra(ll s,ll uu,ll vv)
{
for(int i=1;i<=n;i++)
dis[i]=inf,vis[i]=0;
dis[s]=0;
q.push((node){0,s});
while(!q.empty())
{
node tmp=q.top();
q.pop();
ll x=tmp.pos;
dd d=tmp.dis;
if(vis[x])continue;
vis[x]=1;
for(int i=head[x];i;i=e[i].next)
{
ll y=e[i].to;
if((x==uu&&y==vv)||(x==vv&&y==uu))continue;
if(dis[y]>dis[x]/*d*/+e[i].w)
{
dis[y]=dis[x]/*d*/+e[i].w;
if(uu==-1&&vv==-1)frt[y]=x;
q.push((node){dis[y],y});
}
}
}
}
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&x,&y);
p[i]=point{x,y};
}
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&u,&v);
dd o=sqrt((p[u].x-p[v].x)*(p[u].x-p[v].x)+(p[u].y-p[v].y)*(p[u].y-p[v].y));
// printf("%lf\n",o);
addedge(u,v,o);
addedge(v,u,o);
}
dijkstra(1,-1,-1);
// printf("%lf\n",dis[n]);
ans=inf;
for(int i=n;i!=1;i=frt[i])
{
// cout<<i<<endl;
dijkstra(1,frt[i],i);
ans=min(ans,dis[n]);
}
if(ans==inf)printf("-1");
else printf("%.2lf",ans);
return 0;
}