题目链接https://www.luogu.org/problemnew/show/P1491
就是求第一个点到第n个点的次短路
第一次spfa用前驱记录最短路
第二次spfa删去最短路中的一条边
记录前驱开一个pre数组,在每次松弛操作时,如果d[i]被更新就pre[i]=j;表示当前到第i个点的最短路中,j是i的前驱节点
主函数中,从第n个点开始,即i=n,不断地进行找前驱i=pre[i] 直到pre[i]=1,这个过程中的点连成路径
为什么要去掉最短路上的一条边呢?
因为次短路和最短路至少有一条边不是共有的,需要想想理解一下,,,
code
#include<iostream> #include<cstdio> #include<cmath> #include<vector> #include<queue> #include<cstring> #include<algorithm> using namespace std; const int maxn=208; int n,m; struct p{ int x,y; }po[maxn]; struct re{ int t; double dis; }; vector<re>g[maxn]; int pre[maxn]; double distance(int x1,int y1,int x2,int y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } void spfa1() { queue<int>q; double d[maxn]; bool vis[maxn]; memset(vis,0,sizeof(vis)); for(int i=2;i<=n;i++) d[i]=99999999; d[1]=0;vis[1]=1; q.push(1); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=0;i<g[u].size();i++) { int t=g[u][i].t; double w=g[u][i].dis; if(d[t]>d[u]+w) { d[t]=d[u]+w; pre[t]=u; if(!vis[t]){ q.push(t); vis[t]=1; } } } } } double spfa2(int x,int y) { queue<int>q; bool vis[maxn]; double d[maxn]; memset(vis,0,sizeof(vis)); for(int i=2;i<=n;i++) d[i]=99999999; d[1]=0;vis[1]=1; q.push(1); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=0;i<g[u].size();i++) { int t=g[u][i].t; double w=g[u][i].dis; if((u==x&&t==y)||(u==y&&t==x)) continue; if(d[t]>d[u]+w) { d[t]=d[u]+w; if(!vis[t]){ q.push(t); vis[t]=1; } } } } return d[n]; } int main() { int pj,qj; double dis; double ans=99999999; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d",&po[i].x,&po[i].y); for(int i=1;i<=m;i++) { scanf("%d%d",&pj,&qj); dis=distance(po[pj].x,po[pj].y,po[qj].x,po[qj].y); g[pj].push_back((re){qj,dis}); g[qj].push_back((re){pj,dis}); } memset(pre,0,sizeof(pre)); spfa1(); int now=n; while(pre[now]!=1){ double sxy=spfa2(now,pre[now]); if(ans>sxy) ans=sxy; now=pre[now]; } double sxy=spfa2(now,1); if(ans>sxy) ans=sxy; if(ans==99999999) printf("-1"); else printf("%.2f",ans); return 0; }