洛谷P1443 马的遍历Java AC题解

题目链接 P1443 马的遍历 - 洛谷

解题思路:

这道题目要求计算马从初始位置 (x1, y1) 出发,到达棋盘 n × m 上每个点的最少步数。解题的核心思路是 广度优先搜索(BFS),因为 BFS 天然适合在无权图中寻找最短路径(最少步数)。具体步骤如下:

1. 问题建模:
   - 将棋盘视为一个图,每个格子是一个节点。
   - 如果马可以从一个格子移动到另一个格子(按“日”字走法),则两个节点之间存在一条边。

   -“日”字走法:就是传统象棋中的马走日,所以定义八个方向:

    static int[] dx = {2, 2, 1, 1, -1, -1, -2, -2};
    static int[] dy = {1, -1, 2, -2, 2, -2, 1, -1};

2. BFS 算法:
   - 使用队列存储待访问的节点。
   - 从初始位置 (x1, y1) 开始,步数为 0。
   - 每次从队列取出一个节点,遍历其所有可能的移动方向(8 个方向)。
   - 对于每个新位置:
     - 检查是否在棋盘范围内。
     - 如果未被访问过(即 `dis[a][b] == -1),则更新步数并加入队列。

3. 输出结果:
   - dis[i][j] 存储从 (x1, y1) 到 (i, j) 的最少步数。
   - 若 dis[i][j] == -1,表示该点不可达。

关键点
- BFS 保证最短路径**:由于 BFS 是逐层扩展的,首次访问某个节点时的步数一定是最小的。
- 方向数组**:使用 `dx` 和 `dy` 数组表示马的 8 种移动方式。
- 初始化与边界处理**:
  - dis 初始化为 -1,表示未访问。
  - 每次移动后检查是否越界。

时间复杂度
- O(n × m):每个节点最多入队一次,每次处理 8 个方向,总复杂度为线性。

AC代码:

import java.util.*;
public class Main {
    static int n; // 棋盘的行数
    static int m; // 棋盘的列数
    static int x1; // 马的初始行坐标
    static int y1; // 马的初始列坐标
    static int[][] dis = new int[410][410]; // 存储每个位置的最少步数
    // 马可以移动的8个方向("日"字走法)
    static int[] dx = {2, 2, 1, 1, -1, -1, -2, -2};
    static int[] dy = {1, -1, 2, -2, 2, -2, 1, -1};
    static Queue<int[]> q = new LinkedList<>(); // BFS队列,存储待处理的坐标

    // BFS函数,计算从(x1, y1)出发到所有点的最少步数
    public static void bfs(int x1, int y1) {
        // 初始化距离数组为-1,表示未访问
        for (int[] di : dis) {
            Arrays.fill(di, -1);
        }
        q.clear(); // 清空队列(虽然本题只需调用一次,但养成好习惯)
        q.add(new int[]{x1, y1}); // 起点入队
        dis[x1][y1] = 0; // 起点到自己的距离为0

        while (!q.isEmpty()) {
            int[] t = q.poll(); // 取出队首坐标
            for (int i = 0; i < 8; i++) { // 遍历8个方向
                int a = t[0] + dx[i]; // 计算新坐标
                int b = t[1] + dy[i];
                // 越界检查
                if (a < 1 || a > n || b < 1 || b > m) continue;
                // 已访问过的点跳过
                if (dis[a][b] != -1) continue;
                // 更新新坐标的步数
                dis[a][b] = dis[t[0]][t[1]] + 1;
                // 新坐标入队
                q.add(new int[]{a, b});
            }
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt(); // 输入行数
        m = sc.nextInt(); // 输入列数
        x1 = sc.nextInt(); // 输入初始行坐标
        y1 = sc.nextInt(); // 输入初始列坐标
        bfs(x1, y1); // 执行BFS计算最少步数

        // 输出结果
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                System.out.printf("%-5d", dis[i][j]); // 格式化输出,左对齐占5位
            }
            System.out.println(); // 换行
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值