AI:查找路径是否存在的最快算法?

时间:2013-03-19 19:09:06

标签: algorithm artificial-intelligence path-finding a-star pathfinder

我正在寻找一种寻路算法,用于AI控制2D网格中的实体,需要找到从A到B的路径。它不一定是最短的路径,但需要非常快速地计算。网格是静态的(永远不会改变),一些网格单元被障碍物占用。

我目前正在使用A *,但它对我的目的来说太慢了,因为它总是试图计算最快的路径。当路径不存在时会出现主要的性能问题,在这种情况下,A *将尝试探索太多的单元。

如果路径不必是最短路径,我可以使用哪种算法可以找到比A *更快的路径?

谢谢,

管腔

7 个答案:

答案 0 :(得分:9)

假设您的网格是静态的并且不会更改。在构建网格后,您可以计算图表的连接组件。

然后,您可以轻松检查源和目标顶点是否在组件内。如果是,则执行A *,否则执行A *,因为组件之间不能存在路径。

您可以使用BFS或DFS获取图表的连接组件。

答案 1 :(得分:4)

要查找 a 路径而不是最短路径,请使用任何图形遍历(例如深度优先或最佳优先)。它不一定会更快,事实上它可能会在某些图表上检查比A *更多的节点,因此它取决于您的数据。但是,它将更容易实施,并且常数因素将显着降低。

为了避免在没有路径时搜索路径,您可以创建disjoint sets(在构建图形后一次) very 快速检查两个给定点是否已连接。这需要线性空间和线性时间来构建,并且查找实际上是按时间分摊,但是您仍需要运行完整算法,因为它只会告诉您是否存在路径,不是那条路走的路。

如果你已经预先构建了数据结构,并且在运行时有更多的时间和空间来交换即时最短路径,你可以吃蛋糕并吃掉它: Floyd-Warshall algorithm在相对适度的O(|V|^3)时间内为您提供所有最短路径,考虑到有| V |²(起始,目的地)对,这是降压最大的路径。它计算|V| * |V|矩阵,它可能有点大,但考虑到这是一个整数矩阵,你只需要|V| * |V| * log_2 |V|位(例如,对于1024个顶点,这是1.25 MiB)。

答案 2 :(得分:2)

您可以使用DFSBFS,因为您只想知道这两个顶点是否已连接。这两种算法都在O(|V|)中运行,其中V是图中所有顶点的集合。

如果您的启发式算法需要一些非常重要的时间来计算,请使用这两种算法中的任何一种,否则我认为A *应该与DFS或BFS类似或更好地运行。

作为另一个选项,您可以使用Floyd-Warshall algorithmO(V^3))在创建网格后计算每对顶点之间的最短距离路径,从而在开始时完成所有繁重的工作模拟然后已经存储了哈希中O(1)访问的所有最短路径,或者如果事实证明存在爆炸性,那么你可以保留一个矩阵next,以便next[i][j]存储我们必须从顶点i到顶点j的顶点。因此,我们可以将ij的路径构建为(i, k1=next[i][j]), (k1, k2=next[k1][j]) ... (kr, j)

答案 3 :(得分:1)

如果图表足够小,您可以使用Floyd-Warshall algorithm预先计算所有最短路径。这需要O(|V|²)内存来存储路径,并O(|V|³)时间进行预计算。

显然,对于非常大的图表,这不是一个选项。对于那些你应该使用托马斯的答案并预先计算连接的组件(需要线性时间和内存)以避免最昂贵的A *搜索。

答案 4 :(得分:0)

A *,BFS,DFS和所有其他搜索算法在没有路径时必须检查完全相同数量的节点,因此“首先使用DFS”不是一个好的答案。使用Floyd-Warshall 完全是不必要的。

对于静态图,解决方案很简单;看@ Thomas的回答。对于非静态图,问题更复杂;请参阅this answer了解一个好的算法。

答案 5 :(得分:0)

如果您的迷宫永远不会改变并且任何存在的路径永远存在,您是否可以使用映射算法找到迷宫的“区域”并以某种格式存储它们?内存使用量与节点或单元格数量呈线性关系,速度是访问和比较数组中两个元素的速度。

计算(拆分到区域)可能会耗费更多时间,但在开始时就完成了一次。也许你可以为此目的调整一些洪水填充算法?

不确定从上面是否清楚,但我认为一个例子总是有帮助的。我希望你能原谅我使用PHP语法。

示例(迷宫5x5)([]标志着障碍):

    0 1 2 3 4
  +----------+
0 |[][]   2  |
1 |  [][]    |
2 |    []  []|
3 |  1 []    |
4 |    []    |
  +----------+

索引区域(使用数字哈希而不是'x:y'可能更好):

$regions=array(
    '0:1'=>1,'0:2'=>1,'0:3'=>1,'0:4'=>1,'1:2'=>1,'1:3'=>1,'1:4'=>1,
    '2:0'=>2,'3:0'=>2,'3:1'=>2,'3:2'=>2,'3:3'=>2,'3:4'=>2,'4:0'=>2,
    '4:1'=>2,'4:3'=>2,'4:4'=>2
);

那么你的任务只是找出你的起点和终点是否都在同一个区域:

if ( $regions[$startPoint] == $regions[$endPoint] )
    pathExists();



现在,如果我没有弄错,A *复杂度(速度)取决于起点和终点之间的距离(或解决方案的长度),这可能会用于加快搜索速度。

我会尝试在迷宫中创建一些“结节点”( JN )。这些可以位于一个函数上(快速了解最近的 JN 的位置),并且您将在所有相邻的 JN 之间预先计算路径。

那么你只需要搜索从起点到最近的 JN 的解决方案,并从端点到它最近的 JN (其中所有这些都在同一区域内(上面) ))。现在我可以看到一个场景(如果关于迷宫的复杂性没有很好地选择该功能),它有几个区域,其中一些可能根本没有 JN 或者你的所有< em> JN 落入迷宫中的障碍......所以如果可能的话,手动定义那些 JN 可能会更好,或者让这个 JN 放置功能非微不足道的(考虑到每个地区的面积)。

一旦到达 JN ,您可能会将它们之间的路径编入索引(以快速检索开始和结束之间的预定义路径 JN )或执行另一个A *寻路,除了这一次只在“连接节点”的集合上 - 因为 JN 之间的路径搜索将会更快。

答案 6 :(得分:0)

您可以考虑使用Anytime A *算法(ANA *或其他变体)。

这些将从执行贪婪的最佳第一次搜索开始,以找到初始路径。

然后,通过使用启发式函数运行越来越少的权重,它将进行渐进式改进。

您可以随时取消搜索并找到目前为止找到的最佳路径。