我最近在今年早些时候遇到了来自Spotify黑客挑战的this (Edit: Problem A)有趣的问题,这个问题涉及确定火车卡车路口的切换,以便将列车返回到起点。火车必须朝着它的方向到达,火车不能在轨道上颠倒。在动态有向图中寻找最小循环路径
据我所知,问题可以建模为一个无向(?)图,我们必须从某个顶点找到最短周期,或者检测出没有这样的周期存在。然而,有趣的部分是,对于一个顶点v,与v相邻的顶点依赖于对v取的路径,所以从某种意义上说,图可以被认为是有向的,尽管这个方向是路径依赖的。
我的第一个想法是将每个节点建模为3个单独的顶点A,B和C,其中A和B都是A和B,然后使用宽度优先搜索来构建搜索树直到我们找到了原始的顶点,但是由于上面的警告,这是复杂的,即给定顶点的邻接点取决于我们访问的前一个顶点。这意味着在我们的BFS树中,节点可以有多个父节点。
显然,一个简单的BFS搜索不足以解决这个问题。我知道存在用于检测图形中的周期的算法。一种方法可能是检测所有的周期,然后在每个周期检测路径是否有效。 (即不反转方向)
其他人对解决此问题的方法有任何见解吗?
更新: 我遵循@Karussell在评论中提出的方法。
Here is my solution on github.
诀窍是使用基于边缘的图形,而不是传统的基于顶点的曲线图的情况进行建模。比赛中提供的输入文件可以方便地按边缘指定,因此可以轻松使用此文件构建基于边缘的图形。
程序使用了两个重要的类:Road和Solver。道路有两个整数字段,j1和j2。 j1表示源结,j2表示目标结。每条路都是单向的,这意味着你只能从j1行驶到j2。每条道路还包括相邻道路的链接列表和父路。 Road类还包含静态方法,用于在输入文件中使用的字符串和表示每个交叉点处的A,B和C点的整数索引之间进行转换。
对于输入文件中的每个条目,我们为两个路口之间的每个方向添加两条道路到一个HashMap,一条道路。我们现在列出了在路口之间运行的所有道路。我们只需要通过A,B和C开关将交叉口连接在一起。如果一条公路在Junction.A结束,我们将查找在Junction.B和Junction.C处开始的道路,并将这些道路作为邻接点。 buildGraph()函数返回其目标交叉点(j2)为“1A”==索引0的Road。
此时,我们的图形被构造。要找到最短路径,我简单地使用BFS来遍历图。我们将根标记为未标记,并开始排列根的邻接关系。如果我们找到目标路口为“1A”(索引0)的道路,那么我们已经找到了通过起点的最短周期。一旦我们使用每条道路的父属性重建路径,根据问题的要求适当地设置交换机是一件小事。
感谢Karussell提出这种方法。如果您想以简短的解释将您的评论置于答案中,我会接受它。感谢@Origin,以及。我必须承认,我没有完全遵循你答案的逻辑,但这当然不是说它不正确。如果有人使用你的解决方案解决了这个问题,我会很乐意看到它。
我认为你可以将情况建模为基于边缘的有向图,就像它为转弯限制/成本完成http://algo2.iti.kit.edu/documents/routeplanning/volker_sa.pdf ...或通过这个通过基于节点的图形进行改进http://algo2.iti.kit.edu/1862.php – Karussell
感谢@Karussell,我实施了您建议的解决方案(请参阅编辑。)如果您将它放入,我很乐意接受您的答案回答表格,稍加阐述。 – tronbabylove
请看我的回答。另外,如果你想为真实世界实现这一点(用Java),我会喜欢你对GraphHopper的帮助:)! – Karussell