【问题标题】:How to search an area of the same values in a matrix?如何在矩阵中搜索相同值的区域?
【发布时间】:2012-12-24 07:44:48
【问题描述】:

我有一个这样的整数矩阵:

1 1 1 0 3 3 3 0 2 2
1 1 1 0 3 3 3 0 2 2
0 0 0 0 3 3 3 0 0 0 
2 2 0 0 3 3 3 0 4 4
0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 0 4 4 4 0

我有相同值的不同区域,由“0”分隔,我需要计算矩阵中有多少区域。我的算法基于“0”,每次发现“0”时都会出现一个新区域,所以我增加计数器。问题是我逐行搜索并多次输入同一区域。我只需要计算矩形区域。

【问题讨论】:

  • 举一个例子会让你的问题更容易理解。
  • 矩阵是如何存储的?
  • 区域是否保证是矩形?
  • 这个矩阵的答案是 7

标签: c++ algorithm search matrix


【解决方案1】:

一种简单、快速的算法是遍历所有条目并在遇到每个区域时将其设置为零。这需要 O(N*M) 运行时间(每个条目最多访问两次)和 O(1) 额外内存。

要将区域设置为零,只需记下它开始的列,然后迭代到最右边的列。然后从左到右遍历下面的行,将每个条目设置为零。

Working代码:

int count_regions( int *arr, int rows, int cols ) {
    int region_count = 0;

    for ( int first_index = 0; first_index != rows * cols; ++ first_index ) {
        if ( arr[ first_index ] == 0 ) continue;

        ++ region_count;

        int first_row = first_index / cols, first_col = first_index % cols;
        int last_col;
        for ( last_col = first_col;
              last_col != cols && arr[ first_row * cols + last_col ] != 0;
              ++ last_col ) ;

        for ( int last_row = first_row; 
              last_row != rows && arr[ last_row * cols + first_col ] != 0;
              ++ last_row ) {
            for ( int col = first_col; col != last_col; ++ col ) {
                arr[ last_row * cols + col ] = 0;
            }
        }
    }
    return region_count;
}

【讨论】:

  • 这适用于矩形条目。我发布的通用版本适用于任何形状的条目。
  • @MelNicholson 是的,我做了这个假设。想想看,如果你有一个原始的、未经修改的副本,位图填充更容易计算……
  • 能否给我一个伪代码作为例子,我会更容易理解
  • 您修改了输入数组...添加副本
  • 另外,由于你修改了数组,你不能申请 O(1) 内存。
【解决方案2】:

绘画技巧效果很好。这个想法是你投下一个完全覆盖一个区域的油漆炸弹。伪代码:

for (each space) {
  if (space has been painted or is a border) continue;
  else {
    numAreas++;
    drop paint bomb
  }
}

油漆炸弹的工作原理是这样的:

paint space;
for (each adjacent space) {
  if (space has been painted or space is a border) continue;
  else {
    paint space;
    drop another bomb;
  }
}

【讨论】:

  • 在不允许修改原始矩阵的情况下,是复制矩阵并应用此方法还是创建另一个相同大小的布尔矩阵更方便?
  • 创建一个相同大小的布尔矩阵是可行的。复制矩阵没有帮助。
  • @Buradi 制作自己的副本是最简单的。转换为布尔值或完全更改格式可以提高效率,但肯定会做更多的工作。
  • @Potatoswatter 布尔矩阵以假(未绘制)开始,并且在绘制时每个都标记为真。这样就无需专门标记起始列或对区域的大小或形状进行假设。
【解决方案3】:

一种方法是使用Flood Fill 算法来检测连续区域,如下所示:

假设初始矩阵只有正数,

  • 准备一个counter,设置为-1
  • 对于矩阵中的每个点:
  • 如果单元格为零或负数,则跳过它;否则
  • counter 为负值的单元格开始填充填充
  • 在洪水填充结束后减少计数器

当您到达矩阵的末尾时,counter 的负数将等于连续编号区域的数量减一,即您需要的结果是 -(counter+1)

【讨论】:

    【解决方案4】:

    我一直很喜欢用于隔离组的联合/查找算法。但那是因为我有一个多年前写的旧实现。实现起来没什么大不了,但使用 Flood Fill 可能更合适。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-07
      • 2016-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-21
      • 2022-07-29
      相关资源
      最近更新 更多