欧涛最短路【记录最短路径】
题目链接: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 }