二维差分算法高效解靶场问题

问题分析

给定一个 N×MN \times MN×M 的 01 矩阵(表示每个点是否被子弹中心击中)和子弹尺寸参数 l,rl, rl,r(子弹实际大小为 (2l+1)×(2r+1)(2l+1) \times (2r+1)(2l+1)×(2r+1)),需要输出最终靶子的状态矩阵(1 表示被摧毁,0 表示完好)。

关键规则
  1. 子弹中心被击中(输入矩阵中为 1)会摧毁以其为中心的矩形区域
  2. 摧毁范围:以中心点 (i,j)(i,j)(i,j) 为基准:
    • 行范围:[max⁡(0,i−r),min⁡(N−1,i+r)][\max(0, i-r), \min(N-1, i+r)][max(0,i−r),min(N−1,i+r)]
    • 列范围:[max⁡(0,j−l),min⁡(M−1,j+l)][\max(0, j-l), \min(M-1, j+l)][max(0,j−l),min(M−1,j+l)]
  3. 多个子弹区域可能重叠

高效算法:二维差分数组

使用二维差分数组 可在 O(NM)O(NM)O(NM) 时间复杂度内高效标记所有被摧毁区域,优于暴力方法的 O(NM⋅(2l+1)(2r+1))O(NM \cdot (2l+1)(2r+1))O(NM⋅(2l+1)(2r+1))。

算法步骤
  1. 初始化差分数组

    • 创建大小为 (N+2)×(M+2)(N+2) \times (M+2)(N+2)×(M+2) 的二维数组 diff(多出的空间用于边界处理)
    • 初始化为 0
  2. 标记摧毁区域

    • 遍历输入矩阵的每个点 (i,j)(i,j)(i,j):

      python 复制代码
      if grid[i][j] == '1':
          row_start = max(0, i - r)
          row_end = min(N-1, i + r)
          col_start = max(0, j - l)
          col_end = min(M-1, j + l)
          
          # 差分标记
          diff[row_start][col_start] += 1
          diff[row_start][col_end+1] -= 1
          diff[row_end+1][col_start] -= 1
          diff[row_end+1][col_end+1] += 1
  3. 计算前缀和得到覆盖状态

    • 创建结果数组 res(大小 N×MN \times MN×M)

    • 计算二维前缀和:

      python 复制代码
      for i in range(N):
          for j in range(M):
              # 前缀和公式
              res[i][j] = diff[i][j]
              if i > 0:
                  res[i][j] += res[i-1][j]
              if j > 0:
                  res[i][j] += res[i][j-1]
              if i > 0 and j > 0:
                  res[i][j] -= res[i-1][j-1]
              
              # 转换为 0/1 状态
              res[i][j] = '1' if res[i][j] > 0 else '0'
  4. 输出结果

    • res 按行输出为字符串

示例演示

输入

复制代码
2 2 1 1  # N=2, M=2, l=1, r=1
00
01       # 中心点 (1,1) 被击中

计算过程

  1. 子弹中心 (1,1) 的摧毁范围:[0,1]×[0,1][0,1] \times [0,1][0,1]×[0,1](整个矩阵)

  2. 差分标记:

    复制代码
    diff[0][0] += 1    → (0,0): +1
    diff[0][2] -= 1    → (0,2): -1(边界外)
    diff[2][0] -= 1    → (2,0): -1(边界外)
    diff[2][2] += 1    → (2,2): +1(边界外)
  3. 前缀和计算:

    坐标 计算过程 状态
    (0,0) 1 + 0 + 0 - 0 1 '1'
    (0,1) 0 + 1 + 0 - 0 1 '1'
    (1,0) 0 + 1 + 0 - 0 1 '1'
    (1,1) 0 + 1 + 1 - 1 1 '1'

输出

复制代码
11
11

完整代码实现

python 复制代码
def main():
    import sys
    data = sys.stdin.read().splitlines()
    if not data: 
        return
    
    # 解析第一行
    N, M, l, r = map(int, data[0].split())
    grid = data[1:1+N]
    
    # 初始化差分数组 (N+2) x (M+2)
    diff = [[0] * (M+2) for _ in range(N+2)]
    
    # 处理每个子弹中心
    for i in range(N):
        for j in range(M):
            if grid[i][j] == '1':
                row_start = max(0, i - r)
                row_end = min(N-1, i + r)
                col_start = max(0, j - l)
                col_end = min(M-1, j + l)
                
                # 差分标记
                diff[row_start][col_start] += 1
                diff[row_start][col_end+1] -= 1
                diff[row_end+1][col_start] -= 1
                diff[row_end+1][col_end+1] += 1
    
    # 计算二维前缀和
    res = [['0'] * M for _ in range(N)]
    for i in range(N):
        for j in range(M):
            # 继承上方和左侧的值
            if i > 0:
                diff[i][j] += diff[i-1][j]
            if j > 0:
                diff[i][j] += diff[i][j-1]
            if i > 0 and j > 0:
                diff[i][j] -= diff[i-1][j-1]
                
            # 转换为摧毁状态
            res[i][j] = '1' if diff[i][j] > 0 else '0'
    
    # 输出结果
    for row in res:
        print(''.join(row))

if __name__ == "__main__":
    main()

算法复杂度

  • 时间复杂度 :O(NM)O(NM)O(NM)
    • 遍历输入矩阵:O(NM)O(NM)O(NM)
    • 差分标记操作:每个子弹中心 O(1)O(1)O(1)
    • 前缀和计算:O(NM)O(NM)O(NM)
  • 空间复杂度 :O(NM)O(NM)O(NM)
    • 差分数组:(N+2)×(M+2)(N+2) \times (M+2)(N+2)×(M+2)
    • 结果数组:N×MN \times MN×M

边界处理

  1. 矩阵边界
    • 使用 max(0, ...)min(N-1/M-1, ...) 确保坐标不越界
  2. 差分数组
    • 额外增加 2 行/列防止边界溢出
  3. 重叠区域
    • 差分累加自动处理多次覆盖

此算法能高效处理 103×10310^3 \times 10^3103×103 规模的数据,满足绝大多数应用场景需求。

相关推荐
轻微的风格艾丝凡2 小时前
锂电池 SOC 估计技术综述:成熟算法、新颖突破与车企应用实践
算法·汽车
Codeking__2 小时前
动态规划算法经典问题——01背包问题
算法·动态规划
R-G-B2 小时前
归并排序 (BM20 数组中的逆序对)
数据结构·算法·排序算法
少许极端2 小时前
算法奇妙屋(十二)-优先级队列(堆)
数据结构·算法·leetcode·优先级队列··图解算法
百***93502 小时前
Tomcat报404问题解决方案大全(包括tomcat可以正常运行但是报404)
java·tomcat
qq_281317472 小时前
kubernetes(k8s)-pod生命周期
java·容器·kubernetes
IT界的奇葩2 小时前
代码规范 spring-javaformat使用
java·spring·代码规范
披着羊皮不是狼2 小时前
多用户跨学科交流系统(4)参数校验+分页搜索全流程的实现
java·spring boot
kupeThinkPoem3 小时前
哈希表有哪些算法?
数据结构·算法