【问题标题】:Pathfinding algorithm with specified distance/number of nodes具有指定距离/节点数的寻路算法
【发布时间】:2012-09-20 09:23:51
【问题描述】:

我需要一种算法,它可以为我提供从起始节点到结束节点的路径,但路径必须具有确切数量的节点,否则寻路会失败。

为了展开,我有一个瓷砖网格。只能移动到紧邻的上、下、左或右瓷砖(意思是,没有对角线移动)。在路径中可以使用和不可以使用哪些 tile 有很多规则,但大多数情况下可以归结为一个简单的 bool 来判断该 tile 是否可以使用(这可以在开始算法之前计算. 但是,给我带来麻烦的是,我有一个指定的路径必须具有的距离,这意味着,从一块瓷砖到相邻瓷砖的每一次移动都是 1 的距离,整条路径应该有一个指定的距离,不多也不少。而且,一旦一个瓷砖被踩过(但在算法开始时所有的瓷砖都可用),它就不能再被踩到,有点像玩旧的蛇游戏,你必须注意不要自己吃。

我查看了 Dijkstra/A* 并搜索了寻路算法,但据我所知,所有算法都专注于最短路径,这对我没有多大好处。我不在乎它是哪条路,只要它遵循上述规则即可。

我是否遗漏了什么,是否已经存在这样的算法,或者是否有一种简单的方法可以修改 Dijkstra/A* 来给出这个结果? 由于我不是以英语为母语的人,我可能使用了错误的术语,所以我欢迎为此类算法提供关键字建议。


这是我所说的必须是准确的距离并且不能重复使用同一个图块时的意思。

假设距离必须为 7。现在让我们用 O 标记路径中可以使用的图块,用 X 标记不能使用的图块,用 S 标记起点,用 E 标记目标。

X X X X X X X X O O E S O O X O O O O O O

如果没有距离限制,一个人可以向左走,问题就解决了。 如果有距离限制,而不是“不能踩同一块瓷砖”的限制,可以下一次,然后左,然后右,然后左,然后右,然后左,然后上到达目标. 由于存在两种限制,因此需要向右,向下,向左,向左,向左,向上,然后向右才能到达目标。但是,如果情况是这样的话,就没有有效的路径了。

X X X X X X X X O O E S O O X X O O O X O

如果相关的话,我正在用 C# 开发这个棋盘游戏。

至于最大距离,这里是距离的范围。 玩家将掷骰子并得到数字 1-6。如果玩家得到一个 6,他再次掷骰子,如果他得到另一个 6,一次又一次,直到他没有得到 6。距离是得到的数字加上玩家捡起的物品数量,理论上可以上升到 8,但通常是 0-3,maaaybe 4。

另一方面,我刚刚收到新订单,游戏规则已更改为允许在同一路径上两次踩同一位置,我相信这大大简化了流程,但我会留下这个问题因为我认为它有很好的答案可以帮助处于这种情况的人。

【问题讨论】:

  • 请注意,这个问题是 NP 完全的,通过简化为哈密顿路径问题。另外,请阅读 amit answer here
  • @Haile: 问题是 NP 完全问题,但在这里你应该更加小心,因为问题中的图表有点受限,你需要减少 every 有效减少的哈密顿路径问题。也就是说,问题中的图是网格图,在其上找到哈密顿路径是 NP 完全的。
  • @Nabb 你是绝对正确的。

标签: algorithm path-finding


【解决方案1】:

由于它是 NP 完全的,正如 Haile 所指出的,如果您的问题足够小,这里有一个启发式方法:

  • 查找不包含SE 的半岛(即图表的一部分与其余部分仅通过一个节点相连)并将其删除。
  • 找到从SE 的最短路径P。如果n 小于len(P),则无解。
  • 现在,从SE 进行深度优先搜索,使用以下启发式方法选择首先挖掘的节点。让A 成为深度优先搜索中的当前图块。在欧几里得几何中,将A 的位置投影到直线(SE) 上,并将此点称为A'。尽量保持len(current path) / n 的比率接近len([SA']) / len([SE])。或者更好的是,以某种方式“投射”A 在路径 P 上以获得 A'' 并保持比率 len(current path) / n 接近 len([SA''] along P) / len(P)

我们对您将要处理的具体案例知之甚少,肯定有更多启发式方法可以添加以丢弃深度优先搜索树的部分内容。

【讨论】:

  • 感谢大家,您的所有回答都让我大致了解了如何解决这个问题。 jrouquie,你的解决方案最让我喜欢,所以我会尝试实施它(现在不在家,所以现在不能这样做),看看它如何以及是否会起作用。我不确定什么构成足够小,但我会用距离来编辑问题。
  • 不要忘记停止深度搜索 n,就像 larsmans 写的那样。
【解决方案2】:

由于您遇到的问题是每个步骤的成本为 1,因此称为 depth-limited search 的深度优先搜索的简单变体应该能够找到您想要的路径类型。 Python 中的朴素版本:

def dls(path, goal, depth):
    last = path[-1]
    if len(path) == depth:
        if last == goal:
            return path
    else:
        for n in neighbors(last):
            if allowed(n) and n not in path:
                path.append(n)
                solution = dls(path, depth)
                if solution:
                    return solution
                path.pop()

# call as:
dls([start], goal, depth)

正如其他人所指出的,问题是 NP 完全的,所以不要指望更长的路径长度会出现奇迹。

Russell & Norvig 是这类算法的权威教科书。

【讨论】:

  • 你忘了检查路径是否真的到达了目标:if path[-1]==goal: return path if len(path)==depth else None \ elif len(path) < depth: ...
【解决方案3】:

如果有一个快速算法,你可以插入number of nodes = n,算法会很快告诉你是否有Hamiltonian Path。由于该问题是 NP 完全的,所以您的问题也是如此。

【讨论】:

    【解决方案4】:

    现在问题已经用通常的距离值更新...

    所以,在每个时间步,您最多有 4 个选择,最多有 5+4 = 9 个步骤。这使得少于 49 = 262 144 个潜在路径。先试试蛮力,看看能走多远。

    另外,请注意,反复掷骰子直到得到 6 以外的数字,就相当于抽取 1 到 5 之间的随机数。在电脑游戏中微不足道,并且有物理骰子(谷歌为“5 面骰子”图片)。使用十面骰子也很常见。

    【讨论】:

    • 首先感谢您的回答。问题是必须同时移动,而不是得到 6,移动 6,再次投掷。虽然现在这与更新的规则一样没有实际意义,但我不再有整个问题,因为我没有要求不要两次踩到同一个位置。此外,游戏使用 6 面,因为有时只有 6 种可能的结果,即使移动可以通过获得 6 来扩展。但不是在有争议的问题上扩展,游戏实际上是作为实体棋盘游戏存在的,我只是在制作一个 PC 版本来配合它,所以我无法真正改变它的运行方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-21
    • 2014-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-09
    相关资源
    最近更新 更多