【问题标题】:Algorithm - Find groups of connected tiles算法 - 查找连接的瓦片组
【发布时间】:2012-05-26 21:44:03
【问题描述】:

我对标题感到非常抱歉,但是用几句话来描述我的问题有点困难。我认为帖子的其余部分会更好地解释它! ;)

说明

我基本上有一个瓷砖/对象/符号的二维数组,每当一组瓷砖被特殊瓷砖分隔时,我想将它分成两个(或更多)新的二维数组。

例如,如果我有:

[x][x][0][0]

[0][0][x][0]

[0][0][x][0]

[0][0][0][x]

如果不需要符号 x,那应该给我两个新数组:

[x][x][0][0]

[x][x][x][0]

[x][x][x][0]

[x][x][x][x]

[x][x][x][x]

[0][0][x][x]

[0][0][x][x]

[0][0][0][x]

每组互连瓷砖一个数组。

在我的具体情况下,我将 null 对象作为 x,而将任意对象作为其余对象。基本上,如果我不能从 tile A 到达 tile B 而没有越过 null,那么这两个是两个不同的组。

我已经在脑海中玩了一段时间,我能想到的最好的肯定比 O(n^2) 差得多,因为它们甚至在一开始就起作用了。 Flood fill 突然想到可以用来查找组的东西,但除此之外,我不确定在这种情况下我能想出任何其他类似的问题。

问题

所以我要问的是,您是否碰巧知道将我的问题朝哪个方向处理和/或如何解决它。计算复杂性并不是那么重要,因为我不打算经常执行此操作,也不打算在大型数组上执行此操作。不过,我希望我没有遇到 NP 难题! :3

谢谢!

【问题讨论】:

  • “联合查找”可能是一个解决方案。

标签: arrays algorithm multidimensional-array


【解决方案1】:

我希望我没有遇到 NP 难题!

这远非 NP 问题。

我将解释解决问题的两种不同方法。一个将按照您的预期使用Flood Fill,另一个将使用Disjoint-set 数据结构。

洪水填充

假设您有一个矩阵N x M,其中(row, column) 的位置在不使用时为null,否则它包含一个值。

您需要遍历每个列元素1..M 每行1..N。这很简单:

for row in range(1, N + 1):
  for column in range(1, M + 1):
    if matrix[row][column] is not null:
      floodfill(matrix, row, column)

每次找到非null的值都需要调用Flood Fill算法,后面我会定义Flood Fill方法,原因会更清楚。

def floodfill(matrix, row, column):
  # I will use a queue to keep record of the positions we are gonna traverse.
  # Each element in the queue is a coordinate position (row,column) of an element
  # of the matrix.
  Q = Queue()

  # A container for the up, down, left and right directions.
  dirs = { (-1, 0), (1, 0), (0, -1), (0, 1) }

  # Now we will add our initial position to the queue.
  Q.push( (row, column) )

  # And we will mark the element as null. You will definitely need to
  # use a boolean matrix to mark visited elements. In this case I will simply
  # mark them as null.
  matrix[row][column] = null

  # Go through each element in the queue, while there are still elements to visit.
  while Q is not empty:

    # Pop the next element to visit from the queue.
    # Remember this is a (row, column) position.
    (r, c) = Q.pop()

    # Add the element to the output region.
    region.add( (r, c) )

    # Check for non-visited position adjacent to this (r,c) position.
    # These are:
    #   (r + 1, c): down
    #   (r - 1, c): up
    #   (r, c - 1): left
    #   (r, c + 1): right
    for (dr, dc) in dirs:

      # Check if this adjacent position is not null and keep it between
      # the matrix size.
      if matrix[r + dr][c + dc] is not null
         and r + dr <= rows(matrix)
         and c + dc <= colums(matrix):

        # Then add the position to the queue to be visited later
        Q.push(r + dr, c + dc)

        # And mark this position as visited.
        matrix[r + dr][c + dc] = null

  # When there are no more positions to visit. You can return the
  # region visited.
  return region

如果您跟踪识别的区域数量,您可以修改此算法以在不同的数组中用指定的数字标记每个区域。您会注意到我使用的是队列而不是递归函数,这将使您远离达到最大递归限制。

并集算法

另一个我认为更昂贵的解决方案是使用不相交集数据结构来完成相同的目的。我只会展示对floodfill 方法的更改。

def floodfill(matrix):
  disjoint_set = DisjointSet()

  # Go through each row in the matrix
  for row in range(1, N + 1):

    # Go through each column in the matrix
    for column in range(1, M + 1):

      # Create a set for the current position
      disjoint_set.makeSet(row, column)

      if matrix[row - 1][column] is not null:
        # If the position north of it it is not null then merge them
        disjoint_set.merge((row, column), (row - 1, column))

      if matrix[row][column - 1] is not null:
        # If the position left of it it is not null then merge them
        disjoint_set.merge((row, column), (row, column - 1))

  # You can go through each position identifying its set and do something with it
  for row in range(1, N + 1):
    for column in range(1, M + 1):
      regions[ disjoint_set.find(row, column) ] = (row, column)

  return regions

希望对你有所帮助。

因为你不关心它,所以我没有费心展示复杂性。

【讨论】:

  • Floodfill 是要走的路,O(n) 并且很容易实现
  • 你的意思是O(n^2)。好吧,O(n*m) 在我的解释中。
  • 是的,O(n) 其中 n 是单元格的数量
【解决方案2】:

看来您需要connected-component labeling 算法来生成分离的对象组

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 2015-02-10
    • 2013-04-15
    • 1970-01-01
    • 2012-08-11
    • 2020-10-05
    相关资源
    最近更新 更多