【问题标题】:Find Minimum Time to Occupy Grid查找占用网格的最短时间
【发布时间】:2020-04-13 18:46:39
【问题描述】:

问题: 考虑一位患有皮肤感染的患者,细菌正在迅速蔓延。假设皮肤表面被缩放为大小为 MxN 的矩形网格,并且单元格由 0 和 1 标记,其中 0 表示皮肤上的非受影响区域,1 表示皮肤上的受影响区域。细菌可以在 4 个可能的方向(右、左、上、下)从网格的一个单元格移动到另一个单元格,但一次只能沿一个方向移动到一个单元格,并在 1 秒内影响该单元格。目前正在治疗病人的医生看到了他的情况,想知道在细菌扩散到皮肤和病人死亡之前,他还有多少时间来拯救他。您能帮忙估计一下细菌完全占据皮肤表面所需的最短时间吗?

输入::皮肤的当前状态。 (大小为 MxN 的矩阵,包含 1 和 0,分别代表受影响和未受影响的区域)

输出::覆盖整个网格的最短时间(以秒为单位)。

示例:

输入:

[1 1 0 0 1]
[0 1 1 0 0]
[0 0 0 0 1]
[0 1 0 0 0]

输出: 2 秒

说明:

输入 1 秒后,矩阵如下

[1 1 1 0 1]
[1 1 1 0 1]
[0 1 1 0 1]
[0 1 1 0 1]

下一秒,矩阵完全被1填充

【问题讨论】:

  • 你试过什么?您在解决方案的哪一部分卡住了?
  • M和N的最大值是多少?你有时间限制吗?
  • @Ash 我发现如何从问题入手有困难。
  • 我最初的想法是生成所有下一个可能的状态并从那里达到目标。然后计算所有可能性的最小状态数。如果有其他方法请告诉我。我被困在这一点上。
  • @Damien M 和 N 可以是 2 到 1000

标签: algorithm recursion artificial-intelligence dynamic-programming backtracking


【解决方案1】:

我不会在这里提供详细的解决方案,但希望可以帮助您编写自己的程序。

  1. 第一步是确定要实现的算法类型。最佳方法是为这个问题找到一个简单快速的临时解决方案。在没有这样的解决方案的情况下,对于这类问题,经典的候选是DFS、BFS、A* ...

由于目标是找到最短的解决方案,因此首先考虑 BFS 似乎很自然,因为一旦 BFS 找到解决方案,我们就知道它是最短的,我们可以停止搜索。但是,我们必须考虑避免节点膨胀,因为这不仅会导致巨大的计算时间,还会导致巨大的内存。

  1. 避免节点膨胀的第一个想法是考虑一些1 单元只能在另一个单元中消耗。例如,在发布的图表中,单元格 (0, 0)(左上角)只能扩展到单元格 (1, 0)。然后,经过这个扩展,单元格 (1, 1) 只能移动到单元格 (2, 1)。因此,我们知道将单元格 (1,1) 移动到单元格 (1,0) 是次优的。因此:首先移动这些单元格。

以类似的方式,一旦受感染的细胞仅被其他受感染的细胞包围,就不再需要考虑下一步行动。

最后,有一个受感染细胞的列表以及每个此类细胞可以移动到的未感染细胞的数量会很方便。

  1. 限制节点数量的另一个想法是检测重复项,因为这里可能会存在许多重复项。为此,我们必须定义一种散列。使用的散列函数不需要 100% 有效,但需要快速计算,如果可能,以递归方式计算。如果我们通过在位置 (i, j) 处添加 1 个单元格从 A 图获得 B 图,那么我建议类似

    H(B) = H(A)^f(i, j)
    f(i, j) = a*(1024*i+j)%b

在这里,我使用了 N 和 M 小于 1000 的事实。

每次考虑新图表时,我们必须计算相应的 H 值并检查它是否已经存在于过去的图表集中。

【讨论】:

  • 我能想到的唯一可行的 BFS 是不断排队板的下一个可能的完整状态。你是这个意思吗?
  • 我不确定您所说的“下一个可能的完整状态”是什么意思。我的想法是维护一个“1”列表,与等于 0 的邻居数相关联。不完全确定它会起作用。我可能过于乐观了。我会尝试测试它。 @גלעדברקן
  • 如果板子是 [1 0 0 1 0],那么接下来有两个状态可以添加到 BFS 队列中:[1 1 0 1 1] 和 [1 1 1 1 0]。当然,对于一个 1000x1000 的板,我不确定这有多实用。如果是其他问题,您能否更详细地解释一下 BFS?
  • 基本上就是这样。目标是限制节点的数量。不确定我会成功,我会尝试@גלעדברקן
【解决方案2】:

我不确定在面试的情况下我能走多远。经过一番思考,与其考虑存储多个完整棋盘状态的解决方案,我更愿意考虑一个贪婪的优先级队列,因为下一个要填充的零单元格候选者的强启发式似乎是:

(1) 具有最少相邻受感染细胞(但至少有一个,当然)的健康细胞,

e.g., choose A over B

1 1 B 0 1
0 1 1 0 0
0 0 A 0 1
0 1 0 0 0

和 (2) 通过首先选择健康细胞来打破联系,这些细胞在被感染时会阻止受感染最少的细胞。

e.g., choose A over B

1 1 1 0 1
1 B 1 0 A
0 0 0 0 1
0 1 0 0 0

一个有趣的观察结果是,从技术上讲,任何健康的细胞目的地都可以在距离最近的受感染细胞曼哈顿距离的时间内到达,其中引导这种“爬行”的细胞不断选择使我们更接近目的地的单一动作。但我们知道,与此同时,同样的受感染细胞“蛇”会产生新的“爬虫”,可以到达任何同样远或近的邻居。这让我想知道是否有一种更有效的方法可以根据最远的健康细胞的计数来确定下限。

【讨论】:

  • 确实很有趣。那么问题是证明/检查最优性
【解决方案3】:

这是多智能体寻路问题 (MAPF) 的变体。最近有大量关于这个主题的工作,但早期的现代工作是寻找这个问题的最佳解决方案的一个很好的起点——例如operator decomposition approach

为此,您需要订购代理(细菌)1..k。然后,您将开始搜索,其中为细菌 1 生成所有可能的第一步,然后为细菌 2 生成所有可能的第一步,依此类推,代理的移动将保持在原地,或传播到相邻的未占用地点。每个细菌有 4 种可能的动作,在完整状态之间最多有 4^k 种可能的动作。 (当您尚未为所有 k 个代理分配操作时,会出现部分状态。)操作的数量是指数级的,这意味着您可能会很快遇到资源限制(时间或空间)。但是,只有 2^(MxN) 个可能的状态。 (由于代理不会消失,实际上是 2^(MxN-i),其中 i 是初始细菌的数量。)

每次所有 (k) 个细菌都考虑了一个可能的动作时,你就有了一个新的完整状态。 (然后 k 在下一次迭代中增加。)剩下的最短时间来自填充网格的最浅的完整状态。一些蛮力计算将找到最短的解决方案。 (在大网格的情况下相当多。)

您可以使用 BFS 来查找第一个完全填充的状态。但是,A* 可能会做得更好。作为一种启发式方法,您可以考虑在每个步骤中填充所有单元格的所有相邻位置,然后计算在该模型下填充网格所需的步骤数。这给出了填充整个网格所需时间的下限。

但是,还有更多优化。进行算子分解的原因是您可以命令移动首先采取最佳移动,而不考虑较弱的可能性(例如,所有细菌都不会传播)。您还可以使用部分扩展方法 (EPEA*) 来避免为细菌生成大量明显次优的策略。

如果我在面试时问这个问题,我可能希望看到有人提出问题(什么是行动,什么是状态),提出解决方案的下限(每个细菌都会扩展到每个相邻的单元格) ,想出一个算法,或许可以按照难度递增的顺序分析问题的难度。

【讨论】:

    猜你喜欢
    • 2011-01-27
    • 1970-01-01
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多