欧涛最短路【记录最短路径】

题目链接: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 }
记录最短路径经过的点

猜你喜欢

转载自www.cnblogs.com/yuanweidao/p/11874527.html