题目链接:https://ac.nowcoder.com/acm/contest/1168/C
来源:牛客网
题目描述
已知了飞行器的起点和终点以及n个休息站的坐标,问起点到终点的最短路径是多少?
限制:飞行器不能长期飞行,必须中途在某结点下停下休息。(即连续飞行距离应不大于m)
欧涛师兄很想在师妹面前大展身手,你能帮助他解决这个问题吗?
输入描述:
第一行输入两个数,整数n和浮点数m
第二行输入六个浮点数x1,y1,z1,x2,y2,z2。分别代表起点坐标(x1,y1,z1)和终点坐标(x2,y2,z2)
紧接着下面n行,每行依次输入三个浮点数,代表休息站的坐标(ai,bi,ci),休息站编码依次为1,2……n。
输出描述:
输出满足条件的起点到终点的最短距离长度(结果保留三位小数)。
依次输出飞行器经过站台的编码(休息站编码为1到n,起点编码Start,终点编码End)
若不能到达终点输出“-1”(无双引号)
示例1
输入
4 5 0 0 0 6 6 0 -1 1 0 5 6 0 3 4 0 6 1 0
输出
8.606 Start 3 End
备注:
n<=600
思路:就是朴素版的dijkstra。只不过要存到达终点的路径。纠结半天没出来,归根到底还是对原理不熟悉,这里最关键的就是要记录路径。
这里用一个path数组,path[j]=k表示到达j必须经过k,每次松弛操作找到更短的边都要更新路径。然后这道题就出来了。
#include<stdio.h> #include<math.h> const int maxn=1e6+10; const int inf=0x7fffffff; using namespace std; typedef struct P{ double x,y,z; }Node; int qq,t,n,cnt,vis[600+10],path[600+10],stack[600+10]; double m,Chara[600+10][600+10],dis[600+10]; Node u,v,a[600+10]; void D(int N) { for(int i=0;i<=N;i++) { dis[i] = Chara[0][i]; } dis[0] = 0; vis[0] = 1; for(int i=0;i<=N;i++) { double ans = inf; int k; for(int j=0; j<=N; j++) { if(!vis[j]&&dis[j]<ans) { k = j; ans = dis[j]; } } vis[k] = 1; if(ans==inf)break; for(int j=0; j<=N; j++) { if(!vis[j] && dis[k] + Chara[k][j]<dis[j]) { dis[j] = dis[k] + Chara[k][j]; path[j]=k; } } } } double distance(int x,int y) { return sqrt((a[x].x-a[y].x)*(a[x].x-a[y].x)+(a[x].y-a[y].y)*(a[x].y-a[y].y)+(a[x].z-a[y].z)*(a[x].z-a[y].z)); } int main() { scanf("%d%lf",&n,&m); scanf("%lf%lf%lf",&a[0].x,&a[0].y,&a[0].z); scanf("%lf%lf%lf",&a[n+1].x,&a[n+1].y,&a[n+1].z); for(int i=1;i<=n;i++)scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].z); for(int i=0;i<=n+1;i++) { for(int j=0;j<=n+1;j++) { double pp=distance(i,j); if(pp>m)Chara[i][j]=inf; else if(i==j) Chara[i][j]=0; else Chara[i][j]=pp; } } D(n+1); if(dis[n+1]==inf)printf("-1\n"); else { qq=n+1; cnt=1; while(path[qq]) { stack[cnt++]=path[qq]; qq=path[qq]; } printf("%.3lf\n",dis[n+1]); printf("Start"); for(int i=cnt-1;i>0;i--)printf(" %d",stack[i]); printf(" End"); } return 0; }