Acwing845 八数码

在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

代码与解析

java 复制代码
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();
    }
}
相关推荐
码界奇点12 分钟前
基于Spring Boot与Vue的校园后台管理系统设计与实现
vue.js·spring boot·后端·毕业设计·源代码管理
爱编程的小庄15 分钟前
Rust 发行版本及工具介绍
开发语言·后端·rust
Apifox.2 小时前
测试用例越堆越多?用 Apifox 测试套件让自动化回归更易维护
运维·前端·后端·测试工具·单元测试·自动化·测试用例
sunnyday04262 小时前
Nginx与Spring Cloud Gateway QPS统计全攻略
java·spring boot·后端·nginx
康王有点困2 小时前
Link入门
后端·flink
海南java第二人2 小时前
Spring Boot全局异常处理终极指南:打造优雅的API错误响应体系
java·spring boot·后端
小楼v3 小时前
消息队列的核心概念与应用(RabbitMQ快速入门)
java·后端·消息队列·rabbitmq·死信队列·交换机·安装步骤
小北方城市网3 小时前
接口性能优化实战:从秒级到毫秒级
java·spring boot·redis·后端·python·性能优化
鸡蛋豆腐仙子3 小时前
Spring的AOP失效场景
java·后端·spring
小北方城市网3 小时前
SpringBoot 全局异常处理最佳实践:从混乱到规范
java·spring boot·后端·spring·rabbitmq·mybatis·java-rabbitmq