任务文本:
假设有一天你发现自己在一个矩形岛上。
这个岛的景观可以用一个MxN整数矩阵来描述,每个元素都指定了该岛对应区域的海拔高度。
例如,这是一个 3x3 的小岛:
4 5 4
3 1 5
5 4 1
在雨季,岛上完全被水淹没,低地积水。我们将考虑这样一个岛屿区域的低地,其单元格与高度较大的单元格相邻。在这种情况下,不考虑对角线邻居,海平面为0。在上面的例子中,岛上只有一个低地——这是一个在中间的一个值为1的单元格岛(它与高度为 3、5、5 和 4 的单元格接壤)。
因此,下雨后,岛细胞的高度会发生变化,变为:
4 5 4
3 3 5
5 4 1
我们看到在这个例子中,低地的高度从 1 变为 3,之后水开始溢出到相邻的单元格,然后流入大海。岛上累积的水总量为 2 个立方细胞。
这是一个更复杂的例子:
5 3 4 5
6 2 1 4
3 1 1 4
8 5 4 3
雨后,岛上的地图采用以下形式:
5 3 4 5
6 3 3 4
3 3 3 4
8 5 4 3
在这样一个小岛上,雨后积水的总量高达7立方格!
您的程序必须是以下模板之一。
函数的输入是一个数组数组,输出预期是 int - 每个输入示例的雨季后岛上累积的水总量的值限制:岛屿的大小N 和 M 是 [1, 50] 范围内的整数,取值范围 [1, 1000]。以下是输入数据的示例:
4 5 4
3 1 5
5 4 1
5 3 4 5
6 2 1 4
3 1 1 4
8 5 4 3
2 2 2
2 1 2
2 1 2
2 1 2
对于以上数据,程序函数的结果应该如下:
2
7
0
让我们取两个矩阵:原始的一个,让我们表示它
I。而工作的,与原来的大小相同,但填充了级别的最大可能理论值(我以 10000 的边距取它),让我们表示它W。接下来,我们递归地遍历整个字段,从岛上的每个极端单元开始。递归函数将处理单元的坐标和当前水位作为输入。如果接收到的当前电平低于单元格的初始高度(我们取自I),那么我们接受当前电平等于单元格的高度。因此,我们得到了所有相邻单元格中水可以上升到的水平,如果它们的高度较低的话。在工作矩阵中,我们确定了邻居的最小级别,即 此单元格的最大可能级别。让我提醒您,最初我们将其设为 10000。因此,如果单元格的工作矩阵中的级别结果高于当前级别,那么我们将其与当前级别相等。因此,我们在通过所有邻居时将级别降低到最低限度。还有一个更重要的规则:如果当前级别大于工作矩阵中已经固定的级别,那么我们立即停止递归绕过。一旦W级别较低,这意味着我们已经从流量较低的单元格到达这个单元格,并且没有必要检查更多的邻居,我们在那里并且最大值较低。为了加快工作速度,您可以按高度增加的顺序绕过边界单元。然后,我们将立即用最小值淹没所有可从它们访问的区域。并且在从更高的单元进行分析时,我们不会反复绕过这些区域。
perl 示例
有一个基于明显限制的简单解决方案:
算法:
在 Python 上:
检查问题中的示例:
基于以随机顺序(来自@Mike 的回答和)遍历岛屿的解决方案
max_water_heldover_bruteforce()具有时间复杂度O(ncells * min(ncells, max_height))。它们可以O(ncells * log ncells)通过在低水位到高水位的瓷砖周围走动来升级。这允许每个单元格仅被访问一次。O(n log n) 算法
我们将单元格放在岛边界的堆中(min-heap)。这些细胞中的水位等于它们的高度。
我们按照水位升序访问堆中的所有单元格。
对于访问单元格的每个邻居(上、下、左、右),水位等于
访问单元格中的水位(因为它是最小堆属性中的最小值)
或高度单元格本身(因为水位不能小于单元格的高度)
由于每个单元格只被访问一次,我们立即将保留的水量(单元格中的水位与其高度之间的差)添加到整体结果。
用 Python 实现
这是Jason Yuan对Trapping Rain Water II问题的稍微修改的解决方案:
用法示例。
@David Eisenstat 指出,当问题简化为找到平面图的最小生成树时,可以使用线性 (
O(n)) 算法。@Richard 提到有一些方法适用于万亿细胞问题。请参阅3D 中截留雨水的最大体积。