【问题标题】:Minimum number of iterations in matrix where cell value replaced by maximum of neighbour cell value in single iteration矩阵中的最小迭代次数,其中单元格值替换为单次迭代中相邻单元格值的最大值
【发布时间】:2017-11-01 17:33:57
【问题描述】:

我有一个矩阵,每个单元格中都有值(最小值=1),其中最大值为“最大值”。

一次,我将每个单元格的值修改为其相邻单元格的最大值,即所有 8 个相邻单元格,这同时发生在整个矩阵中。我想在最小迭代次数之后找到所有单元格的值将达到最大值。

这样做的一种蛮力方法是用零填充矩阵,并且

for i in range (1,x_max+1):
    for j in range(1,y_max+1):
    maximum = 0 
        for k in range(-1,2):
            for l in range(-1,2):
                if matrix[i+k][j+l]>maximum:
                    maximum = matrix[i+k][j+l]
        matrix[i][j] = maximum

但是有没有一种更智能、更快捷的方法呢? 提前致谢。

【问题讨论】:

  • matrix[i][j] = maximum 将不起作用,因为后续 if matrix[i+k][j+l]>maximum 需要访问 original 值。建议使用 2 个矩阵。
  • 哦,是的...我们需要 2 个矩阵才能访问原始值。谢谢。著名的。但是不使用蛮力方法仍然可以实现吗?更快更聪明的东西。
  • 为什么是range(-1,2)?对于 8 个邻居,我希望range(-1,1) - inclusive?或者这是某种 python-esse?

标签: python algorithm matrix


【解决方案1】:

我认为这可以通过 BFS(广度优先搜索)来解决。

使用所有具有“最大值”值的矩阵单元同时启动 BFS。

  dis[][]  == infinite // min. distance of cell from nearest cell with 'max' value, initially infinite for all
  Q // Queue
  M[][] // matrix
  for all i,j   // travers the matrix, enqueue all cells with 'max'
    if M[i][j] == 'max' 
       dis[i][j] = 0 , Q.push( cell(i,j) )
  while !Q.empty:
       cell Current = Q.front 
       for all neighbours Cell(p,q) of Current: 
              if dis[p][q] == infinite
                 dis[p][q] = dis[Current.row][Current.column] + 1
                 Q.push( cell(p,q))
       Q.pop()

对于所有 i,j 具有 max(dis[i][j]) 的单元格将是 no。需要的迭代次数。

【讨论】:

    【解决方案2】:

    使用带有“边框”的数组。

    测试边缘条件很繁琐,可以通过使数组在边缘周围变大 1 来避免,每个元素的值为 INT_MIN

    另外,考虑 8 个测试,而不是双嵌套循环

    // Data is in matrix[1...N][1...M], yet is size matrix[N+2][M+2]
    for (i=1; i <= N; i++) {
      for (j=1; j <= M; j++) {
        maximum = matrix[i-1][j-l];
        if (matrix[i-1][j+0] > maximum) maximum = matrix[i-1][j+0];
        if (matrix[i-1][j+1] > maximum) maximum = matrix[i-1][j+1];
        if (matrix[i+0][j-1] > maximum) maximum = matrix[i+0][j-1];
        if (matrix[i+0][j+0] > maximum) maximum = matrix[i+0][j+0];
        if (matrix[i+0][j+1] > maximum) maximum = matrix[i+0][j+1];
        if (matrix[i+1][j-1] > maximum) maximum = matrix[i+1][j-1];
        if (matrix[i+1][j+0] > maximum) maximum = matrix[i+1][j+0];
        if (matrix[i+1][j+1] > maximum) maximum = matrix[i+1][j+1];
        newmatrix[i][j] = maximum
    

    【讨论】:

      【解决方案3】:

      所有现有答案都需要检查矩阵中的每个单元格。如果您还不知道最大值的位置是什么,这是不可避免的,在这种情况下,Amit Kumar's BFS algorithm 具有最佳时间复杂度:O(wh),如果矩阵的宽度为 w 和高度为 h。

      OTOH,也许你已经知道k个最大值的位置,而k相对较小。在这种情况下,以下算法将在 O(k^2*(log(k)+log(max(w, h)))) 时间内找到答案,当 w 或 h 很大时,这要快得多。它实际上并不查看 any 矩阵条目;相反,它运行二进制搜索来寻找候选停止时间(即答案)。对于每个候选停止时间,它会构建一组届时将被max 占据的矩形,并检查是否有任何矩阵单元未被矩形覆盖。

      为了解释这个想法,我们首先需要一些术语。将矩形的顶行称为“开始垂直事件”,将其底边下方的行称为“结束垂直事件”。 “基本间隔”是由任何一对垂直事件跨越的行的间隔,它们之间没有第三个垂直事件(定义这些间隔的事件对可以来自相同或不同的矩形)。请注意,对于 k 个矩形,基本间隔不能超过 2k+1 个——这里不依赖于 h。

      基本思想是从左到右遍历矩阵中对应于水平事件的列:新矩形“开始”的列(左垂直边缘)矩形)或现有矩形“完成”(矩形右垂直边缘右侧的列),跟踪当前覆盖每个基本间隔的矩形数量。如果我们检测到一个由 0 个矩形覆盖的基本区间,我们可以停下来:我们发现一列包含一个或多个在时间 t 尚未覆盖的单元格。如果我们在没有发生这种情况的情况下到达矩阵的右边缘,那么所有单元格都在时间 t 被覆盖。

      这是一个函数的伪代码,用于检查是否有任何矩阵单元在时间t 之前未被覆盖,给定一个长度为k 的数组peak,其中(peak[i].x, peak[i].y) 是第i 个包含max 的位置原始矩阵中的单元格,按 x 坐标的升序排列(因此最左边的包含max 的单元格位于(peak[1].x, peak[1].y))。

      Function IsMatrixCovered(t, peak[]) {
          # Discover all vertical events and basic intervals
          Let vertEvents[] be an empty array of integers.
          For i from 1 to k:
              top = max(1, peak[i].y - t)
              bot = min(h, peak[i].y + t)
              Append top to vertEvents[]
              Append bot+1 to vertEvents[]
      
          Sort vertEvents in increasing order, and remove duplicates.
      
          x = 1
          Let horizEvents[] be an empty array of { col, type, top, bot } structures.
      
          For i from 1 to k:
              # Calculate the (clipped) rectangle that peak[i] will cover at time t:
              lft = max(1, peak[i].x - t)
              rgt = min(w, peak[i].x + t)
              top = max(1, peak[i].y - t)
              bot = min(h, peak[i].y + t)
      
              # Convert vertical positions to vertical event indices
              top = LookupIndexUsingBinarySearch(top, vertEvents[])
              bot = LookupIndexUsingBinarySearch(bot+1, vertEvents[])
      
              # Record horizontal events
              Append (lft, START, top, bot) to horizEvents[]
              Append (rgt+1, STOP, top, bot) to horizEvents[]
      
          Sort horizEvents in increasing order by its first 2 fields, with START considered < STOP.
      
          # Walk through all horizontal events, from left to right.
          Let basicIntervals[] be an array of size(vertEvents[]) integers, initially all 0.
          nOccupiedBasicIntervalsFirstCol = 0
          For i from 1 to size(horizEvents[]):
              If horizEvents[i].type = START:
                  d = 1
              Else (if it is STOP):
                  d = -1
      
              If horizEvents[i].col <= w:
                  For j from horizEvents[i].top to horizEvents[i].bot:
                      If horizEvents[i].col = 1 and basicIntervals[j] = 0:
                          ++nOccupiedBasicIntervalsFirstCol      # Must be START
                      basicIntervals[j] += d
                      If basicIntervals[j] = 0:
                          return FALSE
      
          If nOccupiedBasicIntervalsFirstCol < size(basicIntervals):
              return FALSE         # Could have checked earlier, but the code is simpler this way
      
          return TRUE
      }
      

      上面的函数可以简单地在对 t 的二分查找中调用,查找函数返回 TRUE 的 t 的最小值。

      通过使用Fenwick trees,可以利用受任何矩形开始或结束影响的基本区间集始终是一个区间这一事实,可以去除进一步的 k/log(k) 因子。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-28
        • 1970-01-01
        • 1970-01-01
        • 2021-01-03
        • 1970-01-01
        相关资源
        最近更新 更多