本题为次短路模板题,如何求解次短路,可以先求一次最短路,然后依次尝试删去最短路的一条边,然后再跑一次最短路,记录答案,最后求解出来的便是次短路。
为什么要这么处理,如果删去的边不是最短路上的边,那么不会对最短路造成影响。而次短路与最短路路径一定不会重合,因此可以枚举最短路路径上的边,每次删去一条后再去求解最短路,最后的结果一定是次短路。
如何进行删边操作,可以在求解初始图最短路时记录更新节点的前驱节点,然后在之后求解最短路过程中判断此时的两个节点是否是最短路径一条边上相邻的两个节点。
因此在跑初始图最短路时可以有两种选择,均可进行删边操作:
-
写两种不同的最短路函数;
-
给第一遍传参为
(-1,-1),因为边绝对不会有端点为-1
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define PDI pair<double,int> //宏定义
const int N=205,M=20005;
int n,m,head[N],tot,vis[N];
double dist[N],ans=(INF<<1);
struct node{
int to,nxt;
double w;
}edge[M];
void add(int x,int y,double w){
edge[++tot].to=y;
edge[tot].nxt=head[x];
edge[tot].w=w;
head[x]=tot;
}
struct nod{
double x,y;
int fa;//fa为前驱节点
}d[N];
double cal(double x1,double y1,double x2,double y2){//注意数据类型
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
//堆优化dijkstra
void dijkstra(int x,int y){//注意x,y所表示的意义
for(int i=1;i<=n;i++) dist[i]=INF;
priority_queue<PDI,vector<PDI>,greater<PDI> > q;
dist[1]=0;
q.push(make_pair(0,1));
while(!q.empty()){
PDI t=q.top();
q.pop();
double dis=t.first;
int u=t.second;
vis[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if((u==x&&v==y)||(u==y&&v==x)) continue;//判断该边是否删去
if(dist[v]>dis+edge[i].w){
dist[v]=dis+edge[i].w;
q.push(make_pair(dist[v],v));
if(x==-1&&y==-1) d[v].fa=u;//记录前驱节点
}
}
}
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
double x,y;
cin>>x>>y;
d[i].x=x,d[i].y=y;
}
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
double x1=d[u].x,y1=d[u].y;
double a=d[v].x,b=d[v].y;
double w=cal(x1,y1,a,b);
add(u,v,w),add(v,u,w);
}
dijkstra(-1,-1);//初始图最短路
for(int i=n;i!=1;i=d[i].fa){
dijkstra(i,d[i].fa);
ans=min(ans,dist[n]);
}
if(ans>=INF) puts("-1");
else printf("%.2lf\n",ans);
return 0;
}
475

被折叠的 条评论
为什么被折叠?



