在塔防游戏中,你有一个NxM网格,有一个开始,一个完成,还有一些墙。
敌人从头到尾走最短的路径而不经过任何墙壁(他们通常不会被限制在网格中,但为了简单起见,我们可以说它们是。在任何一种情况下,它们都无法通过对角线“洞”)
问题(至少对于这个问题)是将放置到 K个额外的墙壁,以最大化敌人必须采取的路径。例如,对于K = 14
我的直觉告诉我,如果(因为我希望这样做),这个问题是NP难的我们将其概括为包括在移动到终点之前必须访问的路点,也可能没有航点。
但是,是否有适当的启发式来获得近乎最佳的解决方案?
[编辑] 我发布了一个相关问题here。
答案 0 :(得分:5)
我提出了一种贪婪的方法,它可能接近最优(但我找不到近似因子)。想法很简单,我们应该阻止迷宫中关键位置的细胞。这些地方可以帮助衡量迷宫的连通性。我们可以考虑顶点连通性,我们找到最小的顶点切割,它断开了开始和最终:(s,f)。之后我们删除了一些关键细胞。
要将其转换为图表,请使用双重迷宫。在此图上找到最小(s,f)顶点切割。然后我们检查这个切口中的每个顶点。我们删除一个顶点,它的删除会增加所有 s,f 路径的长度,或者它是否在从s到f的最小长度路径中。消除顶点后,递归重复上述过程k时间。
但是这有一个问题,这就是我们删除一个顶点,它切断从s到f的任何路径。为了防止这种情况,我们可以尽可能地加权切割节点,意味着首先计算最小(s,f)切割,如果切割结果只是一个节点,使其加权并设置一个高权重,如n ^ 3到那个顶点,现在再次计算最小s,f cut,先前计算中的单切顶点因等待而不属于新切削。
但如果s,f之间只有一条路径(经过一些迭代),我们无法改进它。在这种情况下,我们可以使用普通的贪婪算法,例如从s到f的最短路径中删除节点,该路径不属于任何切割。之后我们可以处理最小的顶点切割。
每个步骤的算法运行时间为:
min-cut + path finding for all nodes in min-cut
O(min cut) + O(n^2)*O(number of nodes in min-cut)
并且因为在非常悲观的情况下,min cut中的节点数不能大于O(n ^ 2),算法是O(k n ^ 4),但通常它不应该超过O (k n ^ 3),因为通常min-cut算法支配路径查找,通常路径查找也不需要O(n ^ 2)。
我认为贪婪的选择是模拟退火算法的一个很好的起点。
PS:最小顶点切割类似于最小边缘切割,和类似的方法,如max-flow / min-cut可以应用于最小顶点切割,假设每个顶点为两个顶点,一个V i ,一个V o ,< em>表示输入和输出,也将无向图转换为有向图并不难。
答案 1 :(得分:5)
它可以很容易地显示(证明作为练习给读者),它足以搜索解决方案,以便每个K阻塞都被放在当前的最小长度路线上。请注意,如果有多个最小长度路由,则必须考虑所有这些路径。原因是如果你没有在当前的最小长度路线上放置任何剩余的封锁,那么它就不会改变;因此,您可以在搜索过程中立即对其进行第一次可用的封锁。这甚至加速了蛮力搜索。
但还有更多优化。您也可以随时决定放置下一个封锁,使其成为当前最小长度路线上的第一个封锁,即您工作时如果将封锁放置在路线上的第10个方格上,则标记方块1 ..9作为“永久开放”,直到你回溯。这将再次保存在回溯搜索期间要搜索的指数方块。
然后,您可以应用启发式扫描来减少搜索空间或对其进行重新排序,例如首先尝试那些增加当前最小长度路径长度的封锁布局。然后,您可以在有限的实时时间内运行回溯算法,并选择迄今为止找到的最佳解决方案。
答案 2 :(得分:4)
我相信我们可以将包含的最大流形问题减少到boolean satisifiability,并通过对该子问题的任何依赖来显示NP完全性。因此,the algorithms spinning_plate provided作为启发式precomputing and machine learning is reasonable是合理的,如果我们想在这里犯错误,那么诀窍就是找到最佳启发式解决方案。
考虑如下的董事会:
..S........
#.#..#..###
...........
...........
..........F
这有许多问题导致贪婪和门限解决方案失败。如果我们看第二行:
#.#..#..###
我们的逻辑门是基于0的二维数组排序为[row][column]
:
[1][4], [1][5], [1][6], [1][7], [1][8]
我们可以将其重新渲染为满足块的等式:
if ([1][9] AND ([1][10] AND [1][11]) AND ([1][12] AND [1][13]):
traversal_cost = INFINITY; longest = False # Infinity does not qualify
作为一个不可满足的案例,除了无穷大,我们回溯并将其重新渲染为:
if ([1][14] AND ([1][15] AND [1][16]) AND [1][17]:
traversal_cost = 6; longest = True
我们隐藏的布尔关系属于所有这些门。您还可以证明几何样张不能递归地分形,因为我们总是可以创建一个长度恰好为N-1
宽度或高度的墙,这代表了所有情况下解决方案的关键部分(因此,{{3不会帮助你。)
此外,因为不同行之间的扰动非常重要:
..S........
#.#........
...#..#....
.......#..#
..........F
我们可以证明,如果没有一套完整的可计算几何身份,完整的搜索空间会将自身缩减为N-SAT。
通过扩展,我们还可以证明,当门的数量接近无穷大时,这对于验证和非多项式来解决是微不足道的。不出所料,这就是为什么塔防游戏对人类来说仍然如此有趣。显然,一个更严格的证据是可取的,但这是一个骨架开始。
请注意,您可以显着减少n-choose-k关系中的n项。因为我们可以递归地显示每个扰动必须位于关键路径上,并且因为关键路径总是可以在O(V + E)时间内计算(通过一些优化来加速每次扰动的速度),你可以显着减少你的搜索空间的代价是广度优先搜索添加到电路板上的每个额外塔。
因为对于确定性解决方案我们可以容忍地假设O(n ^ k),所以启发式方法是合理的。因此,我的建议介于divide and conquer和spinning_plate's answer之间,着眼于适用于该问题的机器学习技巧。
第0个解决方案:使用可容忍但非次优的AI,其中spinning_plate提供了两个可用的算法。事实上,这些近似有多少天真的玩家接近游戏,这对于简单游戏应该足够了,尽管具有高度的可利用性。
一阶解决方案:使用数据库。鉴于问题的表述,您还没有充分证明需要动态计算最佳解决方案。因此,如果我们放松接近没有信息的随机板的约束,我们可以简单地预先计算每个板可容忍的所有K
的最优值。显然,这仅适用于少量电路板:每个配置具有V!
个潜在电路板状态,我们无法容忍预计算所有优化,因为V
变得非常大。
二阶解决方案:使用机器学习步骤。当你缩小导致非常高的遍历成本的差距时,推广每一步,直到你的算法收敛,或者找不到比贪婪更好的解决方案。此处有许多算法适用,因此我建议您追逐Soravux's和the classics,以选择在您的计划限制范围内正常运作的算法。
最佳启发式可能是由本地状态感知,递归深度优先遍历生成的简单the literature,在O(V)之后将结果排序最多到最少经常遍历^ 2)遍历。通过这个输出继续贪婪地识别所有瓶颈,并且完全没有使路径成为可能(检查这是O(V + E))。
总而言之,我会尝试这些方法的交集,结合热图和关键路径标识。我认为这里有足够的能够提供一个好的,功能性的几何证明来满足问题的所有限制。
答案 3 :(得分:3)
冒着明显的风险,这是一个算法
1) Find the shortest path
2) Test blocking everything node on that path and see which one results in the longest path
3) Repeat K times
天真地,这将需要O(K *(V + E log E)^ 2)但你可以通过重新计算部分路径来改进2。
正如你所提到的,只是试图打破这条道路是很困难的,因为如果大多数休息只是增加1(或2)的长度,很难找到导致大量收益的阻塞点。
如果从开始和结束之间取minimum vertex cut,您将找到整个图形的阻塞点。一种可能的算法就是这个
1) Find the shortest path
2) Find the min-cut of the whole graph
3) Find the maximal contiguous node set that intersects one point on the path, block those.
4) Wash, rinse, repeat
3)是最重要的部分,为什么这个算法也可能表现不佳。你也可以试试
最后一个可能是最有希望的
如果在整个图形上找到最小顶点切割,您将找到整个图形的阻塞点。
答案 4 :(得分:1)
这是一个想法。在您的网格中,将相邻的墙组合成岛屿,并将每个岛屿视为图形节点。节点之间的距离是连接它们(阻挡敌人)所需的最小墙数。
在这种情况下,您可以通过阻止最便宜的弧来开始最大化路径长度。
答案 5 :(得分:1)
我不知道这是否有用,因为你可以使用你的积分制造新的岛屿。但它可以帮助找出放墙的地方。
我建议使用修改后的广度优先搜索和K长度优先级队列,跟踪每个岛屿之间的最佳K路径。
对于连接墙的每个岛屿,我会假装它是一盏明灯。 (一种只发出水平和垂直光线的特殊光源)使用光线追踪查看灯光可以触及的其他岛屿
说Island1(i1)击中i2,i3,i4,i5但是没有击中i6,i7 ..
然后你会有行(i1,i2),行(i1,i3),行(i1,i4)和行(i1,i5)
将所有网格点的距离标记为无穷大。将起点设置为0。
现在从头开始使用广度优先搜索。每个网格点,将该网格点的距离标记为其邻居的最小距离。
但是..这是抓住..
每次到达两个岛屿之间的一条线()上的网格点,而不是将距离记录为其邻居的最小值,您需要使其成为长度为K的优先级队列。并记录从任何其他行()s到该行()的K个最短路径
然后,这个优先级队列保持不变,直到你到达下一行(),在那里汇总所有优先级问题。
答案 6 :(得分:0)
你没有表明这个算法需要实时,但我可能错了这个前提。然后你可以预先计算块位置。
如果你事先可以做到这一点,然后简单地让AI 构建岩石迷宫摇滚就像它是一种树一样,你可以使用遗传算法来减轻你对启发式的需求。您需要加载任何类型的遗传算法框架,从一组不可移动的块(您的地图)和随机放置的可移动块(AI将放置的块)开始。然后,通过在可移动块上进行交叉和嬗变来进化人口,然后通过对计算出的最长路径给予更多奖励来评估个体。然后,您只需编写资源有效的路径计算器,而无需在代码中使用启发式算法。在你上一代的进化中,你将获得排名最高的个体,这将成为你的解决方案,从而为这张地图提供所需的块模式。
在理想情况下,遗传算法被证明可以在合理的时间内将您带到局部最大值(或最小值),这可能无法通过足够大的数据集上的分析解决方案来实现(即,您的地图足够大)情况)。
您尚未说明要开发此算法的语言,因此我无法提出可能完全符合您需求的框架。
请注意,如果您的地图是动态的,这意味着地图可能会在塔防迭代中发生变化,您可能希望避免使用此技术,因为它可能过于密集而无法在每次波浪中重新演变整个新群体。
答案 7 :(得分:0)
我根本不是算法专家,但看着网格让我想知道Conway's game of life是否可能以某种方式对此有用。有了合理的初始种子和精心挑选的关于塔的诞生和死亡的规则,你可以在很短的时间内尝试许多种子及其后代。
你已经对creeps路径的长度有一定的适应度,所以你可以选择最好的一个。我不知道(如果有的话)它会接近最佳路径,但在解决方案中使用它会是一件有趣的事情。