题目链接:https://ac.nowcoder.com/acm/contest/1168/C
就是普通的最短路,建图时点的距离小于m的连双向边,写了这么久居然不知道怎么记录最短路的路径。在松弛里记录就好了,每次松弛都记录被松弛点的前驱,这样当一个点多次松弛的时候,就可以多次更新它的前驱,当它无法松弛时就是最短路径上的点,也就是记录下来的最后一次松弛的前驱。
然后从终点开始遍历前驱,存在数组中反向输出即可输出最短路径经过的点。
代码如下:

1 #include<bits/stdc++.h>
2 #define mem(a,b) memset(a,b,sizeof(a))
3 const int MAXN = 650;
4 const double inf = 0x3f3f3f3f * 1.0;
5 using namespace std;
6
7 int n, k;
8 double m, dis[MAXN];
9 int head[MAXN], cnt, vis[MAXN];
10 int pre[MAXN];
11
12 struct Node
13 {
14 double x, y, z;
15 }node[MAXN];
16
17 struct Edge
18 {
19 int to, next;
20 double w;
21 }edge[MAXN * MAXN];
22
23 struct N
24 {
25 int pot;
26 double dis;
27 bool operator < (const N &a)const
28 {
29 return dis > a.dis;
30 }
31 }no;
32
33 void add(int a, int b, double c)
34 {
35 cnt ++;
36 edge[cnt].to = b;
37 edge[cnt].next = head[a];
38 edge[cnt].w = c;
39 head[a] = cnt;
40 }
41
42 void dij()
43 {
44 priority_queue<N> Q;
45 no.pot = 0, no.dis = 0;
46 fill(dis, dis + n + 2, inf), mem(vis, 0);
47 dis[0] = 0;
48 Q.push(no);
49 N a;
50 while(!Q.empty())
51 {
52 a = Q.top();
53 Q.pop();
54 if(vis[a.pot])
55 continue;
56 vis[a.pot] = 1;
57 for(int i = head[a.pot]; i != -1; i = edge[i].next)
58 {
59
60 int to = edge[i].to;
61 if(dis[to] > dis[a.pot] + edge[i].w)
62 {
63 dis[to] = dis[a.pot] + edge[i].w;
64 no.pot = to, no.dis = dis[to];
65 pre[to] = a.pot; //松弛即更新记录,那么最后一次松弛一定更新记录到了最短路径上的点
66 Q.push(no);
67 }
68 }
69 }
70 }
71
72 int main()
73 {
74 mem(head, -1), cnt = 0;
75 scanf("%d%lf", &n, &m);
76 scanf("%lf%lf%lf%lf%lf%lf", &node[0].x, &node[0].y, &node[0].z, &node[n + 1].x, &node[n + 1].y, &node[n + 1].z); //起点 终点
77 for(int i = 1; i <= n; i ++)
78 scanf("%lf%lf%lf", &node[i].x, &node[i].y, &node[i].z);
79 for(int i = 0; i < n + 1; i ++)
80 {
81 for(int j = i + 1; j <= n + 1; j ++)
82 {
83 double jl = (node[i].x - node[j].x) * (node[i].x - node[j].x) + (node[i].y - node[j].y) * (node[i].y - node[j].y) + (node[i].z - node[j].z) * (node[i].z - node[j].z);
84 if(jl <= m * m)
85 {
86 add(i, j, sqrt(jl));
87 add(j, i, sqrt(jl));
88 }
89 }
90 }
91 dij();
92 if(dis[n + 1] != inf * 1.0)
93 {
94 printf("%.3lf\n", dis[n + 1]);
95 printf("Start ");
96 int p, len = 0, ans[MAXN];
97 p = n + 1; //终点
98 while(p != 0) //在不等于起点时
99 {
100 ans[len ++] = p;
101 p = pre[p];
102 }
103 for(int i=len-1;i > 0;i--)
104 printf("%d ",ans[i]);
105 printf("End\n");
106 }
107 else
108 printf("-1\n");
109 return 0;
110 }
