Acwing845 八数码

2024-01-10 10:33:12

在2019年y神认为是困难题,2023年便是中等题了。。。嗯。。。

题目

在一个?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

现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。

输入格式

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

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

1 2 3 
x 4 6 
7 5 8 

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

输出格式

输出占一行,包含一个整数,表示最少交换次数。

如果不存在解决方案,则输出??1?1。

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

代码与解析

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

public class Main {

    // BFS求解最小移动步数
    static int bfs(String state) {
        Queue<String> q = new LinkedList<>(); // 存储状态的队列
        Map<String, Integer> d = new HashMap<>(); // 记录状态及对应步数

        q.offer(state); // 初始状态入队
        d.put(state, 0); // 初始状态步数为0

        int[] dx = {-1, 0, 1, 0}, dy = {0, 1, 0, -1}; // 上右下左四个方向

        String end = "12345678x"; // 目标状态
        while (!q.isEmpty()) {
            String t = q.poll(); // 取出队首状态

            if (t.equals(end)) return d.get(t); // 若当前状态为目标状态,则返回步数

            int distance = d.get(t); // 当前状态的步数
            int k = t.indexOf('x'); // 'x'的位置
            int x = k / 3, y = k % 3; // 'x'所在的行和列
            for (int i = 0; i < 4; i++) { // 四个方向尝试移动 'x'
                int a = x + dx[i], b = y + dy[i]; // 计算新位置的行列
                if (a >= 0 && a < 3 && b >= 0 && b < 3) { // 判断新位置是否合法
                    char[] charArray = t.toCharArray();
                    charArray[k] = charArray[a * 3 + b];
                    charArray[a * 3 + b] = 'x';
                    String newStr = String.valueOf(charArray); // 新状态

                    if (!d.containsKey(newStr)) { // 若新状态未访问过
                        d.put(newStr, distance + 1); // 记录新状态的步数
                        q.offer(newStr); // 新状态入队
                    }
                }
            }
        }

        return -1; // 无解时返回-1
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        StringBuilder state = new StringBuilder();
        for (int i = 0; i < 9; i++) {
            state.append(scanner.next()); // 读入初始状态
        }

        System.out.println(bfs(state.toString())); // 输出最小移动步数

        scanner.close();
    }
}

文章来源:https://blog.csdn.net/m0_51547272/article/details/135461619
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。