179.八数码(Java BFS算法)

在一个 3×33×3 的网格中,1∼81∼8 这 88 个数字和一个 x 恰好不重不漏地分布在这 3×33×3 的网格中。

例如:

1 2 3
x 4 6
7 5 8

在游戏过程中,可以把 x 与其上、下、左、右四个方向之一的数字交换(如果存在)。

我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

1 2 3
4 5 6
7 8 x

例如,示例中图形就可以通过让 x 先后与右、下、右三个方向的数字交换成功得到正确排列。

交换过程如下:

1 2 3   1 2 3   1 2 3   1 2 3
x 4 6   4 x 6   4 5 6   4 5 6
7 5 8   7 5 8   7 x 8   7 8 x

把 x 与上下左右方向数字交换的行动记录为 udlr

现在,给你一个初始网格,请你通过最少的移动次数,得到正确排列。

输入格式

输入占一行,将 3×33×3 的初始网格描绘出来。

例如,如果初始网格如下所示:

1 2 3 
x 4 6 
7 5 8 

则输入为:1 2 3 x 4 6 7 5 8

输出格式

输出占一行,包含一个字符串,表示得到正确排列的完整行动记录。

如果答案不唯一,输出任意一种合法方案即可。

如果不存在解决方案,则输出 unsolvable

输入样例:
2 3 4 1 5 x 7 6 8
输出样例
ullddrurdllurdruldr

解题代码

import java.util.*;

class State {
    int[] board;
    int xIndex;
    String moves;

    public State(int[] board, int xIndex, String moves) {
        this.board = board;
        this.xIndex = xIndex;
        this.moves = moves;
    }
}

public class Main {
    static final int[] dx = {0, 0, -1, 1};
    static final int[] dy = {-1, 1, 0, 0};
    static final char[] dir = {'l', 'r', 'u', 'd'};

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int[] board = new int[9];
        int xIndex = 0;

        for (int i = 0; i < 9; i++) {
            String s = scanner.next();
            if (s.equals("x")) {
                board[i] = 0;
                xIndex = i;
            } else {
                board[i] = Integer.parseInt(s);
            }
        }

        String result = solve(board, xIndex);
        System.out.println(result);
    }

    public static String solve(int[] board, int xIndex) {
        int[] target = {1, 2, 3, 4, 5, 6, 7, 8, 0};

        Queue<State> queue = new LinkedList<>();
        queue.offer(new State(board, xIndex, ""));

        Set<String> visited = new HashSet<>();

        while (!queue.isEmpty()) {
            State state = queue.poll();
            if (Arrays.equals(state.board, target)) {
                return state.moves;
            }

            int x = state.xIndex / 3;
            int y = state.xIndex % 3;

            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];

                if (nx < 0 || nx >= 3 || ny < 0 || ny >= 3) continue;

                int nIndex = nx * 3 + ny;
                int[] newBoard = state.board.clone();
                newBoard[state.xIndex] = newBoard[nIndex];
                newBoard[nIndex] = 0;

                String newMoves = state.moves + dir[i];

                String boardStr = Arrays.toString(newBoard);
                if (!visited.contains(boardStr)) {
                    visited.add(boardStr);
                    queue.offer(new State(newBoard, nIndex, newMoves));
                }
            }
        }

        return "unsolvable";
    }
}
  1. 定义状态:

    • 我们需要定义一个状态来表示当前的拼图状态。状态包括当前网格的布局、x的位置以及移动步骤。
    • 我们可以用一个整数数组来表示网格的布局,其中每个数字表示拼图的一个格子的值,而0表示x。
    • x的位置可以用一个整数来表示,例如x在第二行第三列,我们可以将其索引表示为5(行列都从0开始计数)。
    • 移动步骤则是一个字符串,记录了从初始状态到当前状态的所有移动。
  2. 初始化状态:

    • 我们从输入中读取初始网格的布局,并找到x的位置。
    • 将初始状态加入到BFS队列中。
  3. BFS搜索:

    • 在每一次BFS迭代中,我们从队列中取出一个状态,并尝试向四个方向移动x,即左、右、上、下。
    • 对于每个移动,我们生成一个新的状态,并将其加入到队列中,同时更新移动步骤。
    • 如果我们发现某个状态达到了目标状态(即网格布局与目标相同),则返回移动步骤,表示找到了解决方案。
    • 如果队列为空,而没有找到目标状态,说明无法达到目标状态,返回"unsolvable"。
  4. 避免重复状态:

    • 为了避免重复搜索相同的状态,我们使用一个集合来记录已经访问过的状态。这样可以确保我们不会陷入无限循环。
  5. 输出结果:

    • 如果找到了解决方案,则返回移动步骤,表示如何从初始状态到达目标状态。
    • 如果无法找到解决方案,则返回"unsolvable"。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值