机器人活动区域

题目描述

现有一个机器人, 可放置于 M × N 的网格中任意位置, 每个网格包含一个非负整数编号, 当相邻网格的数字编号差值的绝对值小于等于 1 时, 机器人可以在网格间移动.

问题: 求机器人可活动的最大范围对应的网格点数目.

说明: 网格左上角坐标为 (0, 0), 右下角坐标为 (m−1, n−1), 机器人只能在相邻网格间上下左右移动.

输入描述

  • 第 1 行输入为 M 和 N
    • M 表示网格的行数
    • N 表示网格的列数
  • 之后 M 行表示网格数值, 每行 N 个数值 (数值大小用 k 表示), 数值间用单个空格分隔, 行首行尾无多余空格
    • M, N, k 均为整数
    • 1 ≤ M, N ≤ 150
    • 0 ≤ k ≤ 50

输出描述

输出 1 行, 包含 1 个数字, 表示最大活动区域的网格点数目, 行首行尾无多余空格.

示例1

输入:

4 4
1 2 5 2
2 4 4 5
3 5 7 1
4 6 2 4

输出:

6

说明: 如下图, 图中红色区域, 相邻网格差值绝对值都小于等于 1, 且为最大区域, 对应网格点数目为 6.

draw1

示例2

输入:

2 3
1 3 5
4 1 3

输出:

1

说明: 任意两个相邻网格的差值绝对值都大于1, 机器人不能在网格间移动, 只能在单个网格内活动, 对应网格点数目为1.

draw2

题解

使用 广度优先搜索 BFS 求得最大的连接节点数.

Python

import sys

def main():
    # 读取网格的行列值
    parts = input().split()
    rows = int(parts[0])
    columns = int(parts[1])
    assert 1 <= rows <= 150
    assert 1 <= columns <= 150
    # 读取网格中的数值
    grid = []
    for line in sys.stdin.readlines():
        grid.append(list(map(int, line.split())))
        assert len(grid[-1]) == columns
    assert len(grid) == rows
    print(grid)

    # 标记已经访问过了的节点
    visited = [[False] * columns for _row in range(rows)]

    # 四个移动的方向
    directions = ((1, 0), (-1, 0), (0, 1), (0, -1))

    def dfs(grid, visited, x, y):
        if visited[x][y]:
            return 0
        # 先标记当前节点已经访问过
        visited[x][y] = True

        move_range = 1

        # 遍历四个可能的移动方向
        for dx, dy in directions:
            x1 = x + dx
            y1 = y + dy
            # 判断新的节点是否满足条件
            # 1. 在矩形范围内移动
            # 2. 新的节点未被访问过
            # 3. 两个节点上的值相差小于等于1
            if 0 <= x1 < rows and 0 <= y1 < columns and \
                    not visited[x1][y1] and abs(grid[x][y] - grid[x1][y1]) <= 1:
                # 递归访问新的节点
                move_range += dfs(grid, visited, x1, y1)
                #print("move from:", x, y, ", to :", x1, y1)

        # 返回最大能访问的节点数
        return move_range

    # 遍历所有的格子, 找到最大的移动范围
    max_range = 0
    for i in range(rows):
        for j in range(columns):
            # 使用DFS方法, 尝试向四个方向移动
            move_range = dfs(grid, visited, i, j)
            max_range = max(max_range, move_range)

    print(max_range)

if __name__ == "__main__":
    main()

C++

#include <cassert>

#include <array>
#include <iostream>
#include <string>
#include <vector>

int dfs_visit(const std::vector<std::vector<int>>& grid,
              std::vector<std::vector<bool>>& visited,
              int x, int y, int rows, int columns) {
  if (visited[x][y]) {
    return 0;
  }
  // 先标记当前节点状态
  int move_range = 1;
  visited[x][y] = true;

  const std::array<std::array<int, 2>, 4> directions = 
    {std::array<int, 2>{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
  // 开始准备向四个方向访问
  for (const auto dir : directions) {
    int x1 = x + dir[0];
    int y1 = y + dir[1];
    // 判断新的节点是否满足条件
    // 1. 在矩形范围内移动
    // 2. 新的节点未被访问过
    // 3. 两个节点上的值相差小于等于1

    if (0 <= x1 && x1 < rows && 0 <= y1 && y1 < columns && !visited[x1][y1] && 
        std::abs(grid[x][y] - grid[x1][y1]) <= 1) {
      // 递归访问新的节点
      move_range += dfs_visit(grid, visited, x1, y1, rows, columns);
    }
  }

  // 返回移动次数
  return move_range;
}

void solution() {
  // 读取行与列
  int rows = 0;
  int columns = 0;
  std::cin >> rows >> columns;
  assert(rows > 0 && columns > 0);
  // 换行符
  std::string line;
  std::getline(std::cin, line);

  // 读取二维数组
  std::vector<std::vector<int>> grid;
  for (int row = 0; row < rows; ++row) {
    std::vector<int> nums(columns);
    for (int& num : nums) {
      std::cin >> num;
    }
    grid.emplace_back(nums);
    // 换行符
    std::getline(std::cin, line);
  }

  // 标记已经访问过了的节点
  std::vector<std::vector<bool>> visited(rows, std::vector<bool>(columns, false));

  int max_move_range = 0;

  // 接下来遍历所有的节点, 找到最大的访问范围.
  for (int row = 0; row < rows; ++row) {
    for (int column = 0; column < columns; ++column) {
      // 如果该节点已经访问过, 就忽略
      if (!visited[row][column]) {
        const int move_range = dfs_visit(grid, visited, row, column, rows, columns);
        max_move_range = std::max(max_move_range, move_range);
      }
    }
  }

  // 打印结果
  std::cout << max_move_range << std::endl;
}

int main() {
  solution();
  return 0;
}