【问题标题】:Problem with terminated paths in simple recursive algorithm简单递归算法中终止路径的问题
【发布时间】:2010-08-20 23:18:39
【问题描述】:

首先:这不是家庭作业,这是我的一个爱好项目。

背景: 对于我的 Java 益智游戏,我使用一个非常简单的递归算法来检查“地图”上的某些空间是否在放置一块后变得孤立。在这种情况下,隔离意味着:不能放置任何碎片。

当前算法:

public int isolatedSpace(Tile currentTile, int currentSpace){
        if(currentTile != null){
            if(currentTile.isOpen()){
                currentTile.flag(); // mark as visited
                currentSpace += 1;
                currentSpace = isolatedSpace(currentTile.rightNeighbor(),currentSpace);
                currentSpace = isolatedSpace(currentTile.underNeighbor(),currentSpace);
                currentSpace = isolatedSpace(currentTile.leftNeighbor(),currentSpace);
                currentSpace = isolatedSpace(currentTile.upperNeighbor(),currentSpace);
                if(currentSpace < 3){currentTile.markAsIsolated();} // <-- the problem
            }
        }
        return currentSpace;
    }

这段代码返回起始磁贴所在的空白空间的大小。这部分代码按预期工作。但是我遇到了一个关于瓷砖标记的问题,这就是使这个问题的标题相关的原因;)

问题: 问题是某些图块永远不会“重新访问”(它们返回一个值并终止,因此永远不要从以后的化身中获取返回值来更新空白空间的大小)。这些“被遗忘”的瓦片可以是大空间的一部分,但仍被标记为隔离,因为它们在进程开始时被访问,当时 currentSpace 的值较低。

问题: 如何改进此代码,以便在没有太多开销的情况下为图块设置正确的值?我可以想到丑陋的解决方案,例如重新访问所有标记的图块,如果它们具有正确的值,检查邻居是否具有相同的值,如果没有更新等。但我敢肯定 Stack Overflow 上有聪明的人有更好的想法; )


更新: 我做了一些改变。

public int isolatedSpace(Tile currentTile, int currentSpace, LinkedList<Tile> visitedTiles){
        if(currentTile != null){
            if(currentTile.isOpen()){
                // do the same as before
                visitedTiles.add(); 
            }
        }
        return currentSpace;
    }

还有marktiles函数(只在返回的spacesize小于给定值时调用)

marktiles(visitedTiles){
       for(Tile t : visitedTiles){
            t.markAsIsolated();
       }
}

这种方法符合 Rex Kerr 的回答,至少如果我理解他的想法的话。

【问题讨论】:

  • 另外,我想指出,根据所涉及的特定部分,如果形状不佳,即使是大面积也可能被“隔离”。例如,如果您没有线性片段,则无法填充 20 个空格长的线条。如果这很重要,您可能不得不尝试将每件作品放在每个位置/方向;标记任何有效位置所覆盖的方格,然后在完成后反转标记以获得不可用的空间。

标签: java algorithm recursion


【解决方案1】:

这不是一个通用的解决方案,但只有当它们出现在两个或更少空间的区域中时,您才将它们标记为孤立的。您不能将此测试简化为“如果 (a) 它没有开放的邻居或 (b) 恰好有一个开放的邻居并且该邻居没有其他开放的邻居,那么该空间是孤立的”。

【讨论】:

  • 这是个好主意,谢谢!然而,隔离空间的大小会随着拼图中使用的碎片而变化。棋子形状各异,有三种尺寸:三块、四块、五块。因此,少于 3 块瓷砖的空间始终是孤立的,但当只有 4 或 5 个块可用时,少于 4 块瓷砖也会成为孤立空间。
  • 我认为可能是这样。这是一个可能使您的算法更精简的想法:为每个空间添加一个“空间 ID”字段。当您放置或移除一块时,为空间选择一个新的、新鲜的 id,然后执行递归洪水填充算法,用新的 id 标记每个连接的空间,并跟踪您标记了多少空间。如果您的空间 id 有足够的位(int 可能很好,long 可能过大),您不需要保留单独的已访问图块列表或执行单独的标记阶段。
【解决方案2】:

您需要有一个两步过程:收集有关空间是否隔离的信息,然后分别标记为隔离。因此,您需要首先计算所有空格(使用一个递归函数),然后在条件通过时标记所有连接的空格(使用不同的递归函数)。

【讨论】:

  • 感谢您的解决方案!你所描述的似乎是我在此期间实施的。每个被标记的图块现在都添加到一个名为visitedTiles 的列表中。在计算完空间(并且知道最终大小)之后,调用称为 markTiles 的第二个函数(仅当空间的总大小小于某个值时)将列出的图块标记为孤立的。这似乎工作正常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-21
  • 2016-01-23
  • 1970-01-01
  • 2011-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多