是否有一条从城市到城市b的路线不超过x天?

时间:2013-04-11 00:40:43

标签: algorithm graph graph-algorithm shortest-path

我在接受贸易公司采访时被问到这个问题,

你乘坐公共汽车在全国各地旅行,公共汽车可以停在任何可能的C市,你需要找到从城市到城市的路。总共有B巴士,每辆巴士都在两个城市之间旅行。所有公共汽车每天都行驶,例如每辆公共汽车x在第d1天离开一些城市c1并在另一天d2(d2> d1)到达另一个城市b1。假设如果您在第d天到达某个城市,您可以在第d天或之后赶上离开城市的任何公共汽车。

B巴士给你a1,b1,d1和d2。描述一种算法,该算法在不超过D天的时间内确定是否存在从城市a到城市b的路线,并分析运行时间。

我最初尝试将问题建模到最短路径算法中,但我当时无法弄清楚,我搞砸了采访。

4 个答案:

答案 0 :(得分:1)

我想如果你有一天开始(似乎并非如此),应用Dijkstra's algorithm应该很容易。

为问题创建图表是微不足道的。每个节点都是一个城市,每个总线都是从一个节点到另一个节点的有向边。一般来说,边缘的权重并没有真正定义(我们不能只计算行程时间),而是在我们处理它时确定。

所以,将问题减少到您知道开始日的多个子问题,如下所示:

从有公共汽车到其他城市。因此,总线b i 从a开始 i 从a到b i 到日结束 i 。对于这些总线中的每一个,从日终 i 的b i 开始创建一个子问题(并记住start i )。

在开始日和城市时做Dijkstra:

在浏览图表时,我们需要跟踪当天。

当从第d1天在城市c1生成邻居时,对于从c1到c2的总线的每个城市c2,我们生成从c1到c2的最早的总线(在c1离开的地方) ; =当天)(如果公共汽车从c1到c2可能需要不同的天数,请考虑最早到达c2)。 c2的值只是从原始起始日(从上面开始 i )到公共汽车到达c2的那天的天数。

<强>优化

您不需要在每个子问题上执行完整的运行Dijkstra,如果您在某一天到达某个城市,那么在同一天到达该城市的任何下一个子问题都会从那里开始有相同的路径。同时完成所有这些工作不应该太困难,并且应该比一次完成这些工作更好。

有人可以提出启发式功能,以便能够应用A*

如果我错过了什么,请随时指出。

答案 1 :(得分:0)

有趣的问题。这是我的尝试。如果我忽略了重要的事情,或者我的解决方案中的某些内容不清楚,请告诉我。

提示1:如果问题看起来很难,请将其简化为更简单的方法。解决更简单的问题,看看你是否可以将解决方案推广到更难的案例。

让我们在这里应用这个技巧。我们知道公共汽车在两个城市之间。为了简化假设,如果公共汽车从一个城市到另一个城市,我们总是可以在这两个节点之间进行。因此,建立一个无向图,其中顶点是城市。现在在顶点i和j之间存在一条边,如果总有一条从i到j的总线(与从j到i的相同)。现在在这种情况下,问题就在于我们是否有兴趣从a开始并以b的长度&lt; n,最短路径的长度是否小于n。太好了!

现在让我们回到更难的问题。我们构建了两个图形G_1和G_2,G_1表示我们可以获得的地方,因为当天是奇数编号(如第1天),G_2代表我们可以获得的地方,因为当天是偶数编号(如第2天)。现在,这两个图都与以前不同。现在我们将这两个图组合起来形成图G. G的顶点只是G_1联合G_2。现在对于G_1中的每个有向边,表示起始顶点s和结束顶点t。将G_1中的顶点(作为G的子图)连接到G_2中的顶点t(作为G的子图)。对于G_2中的每个有向边,表示起始顶点s和结束顶点t。将G_2中的顶点(作为G的子图)连接到G_1中的顶点t(作为G的子图)。 G中的所有有向边都具有权重1.现在的问题是,在长度

我们的想法是将G_2上的两个图形G_1叠加在一起,以便我们考虑到路线在偶数天和奇数天都会发生变化。

答案 2 :(得分:0)

这是Haskell中的一个例子,它有真正的慢速总线,构建从目的地回到原点的路线:

import Data.List (elemIndex)
import Data.Maybe (fromJust)

cities = ["New York", "Philadelphia", "Washington", "Buffalo"]
buses = [([0,1],2), ([0,2],1), ([1,2],1), ([2,3],4)] --buses (cities a1 b1 as indexes, num days of travel)

solve origin destination maxDays = do
  lastBus <- filter ((== fromJust (elemIndex destination cities)) . last . fst) buses
  solve' [lastBus] where
    solve' result 
      | sum (map snd result) > maxDays                   = []
      | cities !! (head . fst . head $ result) == origin = 
          [(map (map (cities !!) . fst) result, show (sum . map snd $ result) ++ " Days Travel")]
      | otherwise = 
          let potentialBuses = filter ((== (head . fst . head $ result)) . last . fst) buses
          in if null potentialBuses 
                then []
                else do
                  bus <- potentialBuses
                  solve' (bus:result)


OUTPUT:
*Main> solve "New York" "Buffalo" 6
[([["New York","Washington"],["Washington","Buffalo"]],"5 Days Travel")]

*Main> solve "New York" "Buffalo" 3
[] --trip longer than D

*Main> solve "New York" "Washington" 3
[([["New York","Washington"]],"1 Days Travel"),
 ([["New York","Philadelphia"],["Philadelphia","Washington"]],"3 Days Travel")]

答案 3 :(得分:0)

还有另一种方法,你会偶尔发现。它基于一个矩阵,定义了城市之间可能的过渡。假设矩阵是M,那么如果存在从城市j到城市i的道路,则M [i,j]为1,否则为0.通过以起始城市的单位向量开始并将该向量与转移矩阵相乘,将在一步到位的所有城市中获得值为零的向量。您可以按要求的天数重复此步骤。

在对案例进行建模时,问题在于您有一个加权图,即并非每个转换都需要相同的时间。但是,该成本是一个整数,因此您可以在需要一天以上的路线中引入人工停止(即顶点)来建模。然后你会得到一个未加权的图表。此外,您可以从问题中假设权重较低,因此可能不会产生太多开销。

由于矩阵乘法是关联的,因此您可以将矩阵与其自身相乘多次,然后将其提供给初始矢量。由于实际值不感兴趣,只有它们是0还是1,您可能能够进一步减少这个并有效地对矩阵进行位打包。此外,您可以将MxMxMxM计算为(MxM)x(MxM)以减少开销。然后,还可以对可以收获的矩阵乘法(Strassen算法,IIRC)进行一些优化。

注意:我知道这个描述有点粗略,只需给我留言,我会尝试澄清它。