用队列解决骑士移动问题

x33g5p2x  于2022-03-05 转载在 其他  
字(2.2k)|赞(0)|评价(0)|浏览(178)

一 问题描述

计算骑士从一个位置移动到另外一个位置所需的最少移动次数。骑士移动规则如下图。

输入:测试用例包含3行。

第1行:表示棋盘的长度 L,范围在 [4,300],棋盘的大小为 L * L。

第2行:骑士在棋盘的开始位置。

第3行:骑士在棋盘的结束位置。

输出:输出骑士从起点移动到终点所需的最少移动次数。如果起点和终点相等,则移动次数为零。

下面是三组测试用例的结果。

| <br>输入<br> | <br>输出<br> |
| <br>8<br><br>(0,0)<br><br>(7,0)<br> | <br>5<br> |
| <br>100<br><br>(0,0)<br><br>(30,50)<br> | <br>28<br> |
| <br>10<br><br>(1,1)<br><br>(1,1)<br> | <br>0<br> |

二 算法设计

本问题求解棋盘从起点到终点最短距离问题可以使用队列进行广度优先搜索,步骤如下:

1 如果起点正好等于终点,则返回 0。

2 将起点放入队列。

3 如果队列不为空,则队头出队,否则扩展8个方向,如果找到目标,则立即返回步数加1,否则判断是否越界;如果没有越界,则将步数加1,并放入队列,标记棋盘已访问。如果骑士的当前位置为(x,y),则移动时,当前位置坐标加上偏移量即可。例如骑士从当前位置移到右上角的位置(x-2,y+1),如下图所示。

8个方向的位置偏移如下。

x 方向:{-2,-2,-1,-1,1,1,2,2}

y 方向:{1,-1,2,-2,2,-2,1,-1}

三 实现

package concurrent;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

/**
* @className: KnightMove
* @description: 骑士移动问题
* @date: 2022/3/5
* @author: cakin
*/
public class KnightMove {
    public static void main(String[] args) {
        int dx[] = {-2, -2, -1, -1, 1, 1, 2, 2};
        int dy[] = {1, -1, 2, -2, 2, -2, 1, -1};
        Scanner input = new Scanner(System.in);
        // 棋盘的大小
        int lengh = input.nextInt();
        // 标记棋盘位置是否访问过
        boolean[][] visitFlag = new boolean[lengh][lengh];
        // 开始位置
        int sx = input.nextInt();
        int sy = input.nextInt();
        // 结束位置
        int ex = input.nextInt();
        int ey = input.nextInt();
        // 中间位置
        int tx;
        int ty;
        if (sx == ex && sy == ey) {
            System.out.println("移到步数为0");
            return;
        }
        // 定义一个队列
        Queue<Point> queue = new LinkedList<>();
        // 开始位置
        Point start = new Point();
        start.x = sx;
        start.y = sy;
        start.step = 0;
        // 进入队列
        queue.offer(start);
        int step;
        int x;
        int y;
        while (!queue.isEmpty()) {
            // 取队列头元素,同时把这个元素弹出
            start = queue.poll();
            x = start.x;
            y = start.y;
            step = start.step;
            for (int i = 0; i < 8; i++) {
                tx = x + dx[i];
                ty = y + dy[i];
                if (tx == ex && ty == ey) {
                    System.out.println("移到步数为" + (step + 1));
                    return;
                }
                if (tx >= 0 && tx < lengh && ty >= 0 && ty < lengh && !visitFlag[tx][ty]) {
                    // 中间位置
                    Point node = new Point();
                    node.x = tx;
                    node.y = ty;
                    node.step = step + 1;
                    // 满足条件入队
                    queue.offer(node);
                    visitFlag[tx][ty] = true;
                }

            }
        }
    }
}

/**
* @className: Point
* @description: 描述棋盘上的一个点
* @date: 2022/3/5
* @author: cakin
*/
class Point {
    // x 坐标
    public int x;
    // y 坐标
    public int y;
    // 步数
    public int step;
}

四 测试

绿色为输入,白色为输出

相关文章