找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4010|回复: 0

【最短路】速度限制

[复制链接]
发表于 2012-2-3 13:16:00 | 显示全部楼层 |阅读模式
【问题描述】    在这个繁忙的社会中,我们往往不再去选择最短的道路,而是选择最快的路线。开车时每条道路的限速成为最关键的问题。不幸的是,有一些限速的标志丢失了,因此你无法得知应该开多快。一种可以辩解的解决方案是,按照原来的速度行驶。你的任务是计算两地间的最快路线。    你将获得一份现代化城市的道路交通信息。为了使问题简化,地图只包括路口和道路。每条道路是有向的,只连接了两条道路,并且最多只有一块限速标志,位于路的起点。两地A和B,最多只有一条道路从A连接到B。你可以假设加速能够在瞬间完成并且不会有交通堵塞等情况影响你。当然,你的车速不能超过当前的速度限制。【输入】    输入文件speed.in的第一行是3个整数N,M和D(2<=N<=150),表示道路的数目,用0..N-1标记。M是道路的总数,D表示你的目的地。接下来的M行,每行描述一条道路,每行有4个整数A(0≤A<N),B(0≤B<N),V(0≤V≤500)and L(1≤L≤500),这条路是从A到B的,速度限制是V,长度为L。如果V是0,表示这条路的限速未知。如果V不为0,则经过该路的时间T=L/V。否则T=L/Vold,Vold是你到达该路口前的速度。开始时你位于0点,并且速度为70。【输出】        输出文件speed.out仅一行整数,表示从0到D经过的城市。        输出的顺序必须按照你经过这些城市的顺序,以0开始,以D结束。仅有一条最快路线。【样例】speed.in6 15 10 1 25 680 2 30 500 5 0 1011 2 70 771 3 35 422 0 0 222 1 40 862 3 0 232 4 45 403 1 64 143 5 0 234 1 95 85 1 0 845 2 90 645 3 36 40speed.out0 5 2 3 1拆點+SPFA。

普通的SPFA中,用dist數組保存臨時最短距離,並用標誌數組保存是否在隊列中。

而此題,當前點臨時最短距離(即題目中的最短時間),還與從上一個來的初速度有關,所以將dist多加一個參數即前一個點的編號,並且在隊列中要記錄走過當前這條邊的速度。
Accode:
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <cstdlib>
  4. #include <bitset>
  5. #include <cmath>
  6. using std::bitset;
  7. const char fi[] = "speed.in";
  8. const char fo[] = "speed.out";
  9. const int maxN = 210;
  10. const int SIZE = 1050000;
  11. const int MOD = (1 << 20) - 1;
  12. const int MAX_int = 0x3fffff00;
  13. const int MIN_int = -MAX_int;
  14. const double MAX_double = 1e198;
  15. const double MIN_double = -MAX_double;
  16. const double zero = 1e-12;
  17. struct Edge
  18.   {int dest, _d, _v; Edge *next; };
  19. struct Que
  20. {
  21.   int Last, ths, _v;
  22.   Que(int la, int th, int v)
  23.     {Last = la; ths = th; _v = v; }
  24.   Que() {Last = ths = _v = 0; }
  25. };
  26. Edge *edge[maxN];
  27. double dist[maxN][maxN];
  28. Que q[SIZE];
  29. bitset <maxN> marked[maxN];
  30. int pre[maxN][maxN];
  31. int n, m, start, finish, f, r;
  32.   void init_file()
  33.   {
  34.     freopen(fi, "r", stdin);
  35.     freopen(fo, "w", stdout);
  36.   }
  37.   inline void insert(int u,
  38.     int v, int _d, int _v)
  39.   {
  40.     Edge *p = new Edge;
  41.     p -> dest = v;
  42.     p -> _d = _d;
  43.     p -> _v = _v;
  44.     p -> next = edge[u];
  45.     edge[u] = p;
  46.   }
  47.   void readdata()
  48.   {
  49.     scanf("%d%d%d", &n, &m, &finish);
  50.     for (int i = 0; i < m; ++i)
  51.     {
  52.       int u, v, _d, _v;
  53.       scanf("%d%d%d%d", &u, &v, &_v, &_d);
  54.       insert(u, v, _d, _v);
  55.     }
  56.   }
  57.   inline void Enq(int Last, int ths, int _v)
  58.   {
  59.     marked[Last].set(ths);
  60.     ++r;
  61.     r &= MOD;
  62.     q[r] = Que(Last, ths, _v);
  63.   }
  64.   inline Que Deq()
  65.   {
  66.     ++f;
  67.     f &= MOD;
  68.     marked[q[f].Last].reset(q[f].ths);
  69.     return q[f];
  70.   }
  71.   void Spfa()
  72.   {
  73.     while (f != r)
  74.     {
  75.       Que Now = Deq();
  76.       int ths = Now.ths;
  77.       int _v = Now._v;
  78.       int Last = Now.Last;
  79.       for (Edge *p = edge[ths]; p; p = p -> next)
  80.       {
  81.         if (p -> _v) _v = p -> _v;
  82.         double t = p -> _d / (double)_v;
  83.         if (dist[Last][ths] + t < dist[ths][p -> dest])
  84.         {
  85.           dist[ths][p -> dest] = dist[Last][ths] + t;
  86.           pre[ths][p -> dest] = Last;
  87.           if (!marked[ths].test(p -> dest))
  88.             Enq(ths, p -> dest, _v);
  89.         }
  90.         _v = Now._v; //要記住每次還原速度。
  91.       }
  92.     }
  93.   }
  94.   void print(int Last, int ths)
  95.   {
  96.     if (ths == 0) return;
  97.     print(pre[Last][ths], Last);
  98.     printf("%d ", Last);
  99.   }
  100.   void work()
  101.   {
  102.     for (int i = 0; i < n; ++i)
  103.      for (int j = 0; j < n; ++j)
  104.       dist[i][j] = MAX_double;
  105.     dist[0][start] = 0;
  106.     Enq(0, start, 70);
  107.     Spfa();
  108.     double Min = MAX_double;
  109.     for (int i = 0; i < n; ++i)
  110.       Min = std::min(Min, dist[i][finish]);
  111.     for (int i = 0; i < n; ++i)
  112.      if (fabs(Min - dist[i][finish]) < zero)
  113.       {print(i, finish); break; }
  114.     printf("%d", finish);
  115.   }
  116. int main()
  117. {
  118.   init_file();
  119.   readdata();
  120.   work();
  121.   exit(0);
  122. }
复制代码


作者:Whjpji 发表于2012-2-3 9:58:55 原文链接

您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-12-22 16:52 , Processed in 0.017433 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表