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();
    }
}
相关推荐
humors22114 分钟前
服务端开发案例(不定期更新)
java·数据库·后端·mysql·mybatis·excel
Easonmax2 小时前
用 Rust 打造可复现的 ASCII 艺术渲染器:从像素到字符的完整工程实践
开发语言·后端·rust
百锦再3 小时前
选择Rust的理由:从内存管理到抛弃抽象
android·java·开发语言·后端·python·rust·go
小羊失眠啦.3 小时前
深入解析Rust的所有权系统:告别空指针和数据竞争
开发语言·后端·rust
q***71853 小时前
Spring Boot 集成 MyBatis 全面讲解
spring boot·后端·mybatis
大象席地抽烟3 小时前
使用 Ollama 本地模型与 Spring AI Alibaba
后端
程序员小假3 小时前
SQL 语句左连接右连接内连接如何使用,区别是什么?
java·后端
小坏讲微服务3 小时前
Spring Cloud Alibaba Gateway 集成 Redis 限流的完整配置
数据库·redis·分布式·后端·spring cloud·架构·gateway
方圆想当图灵4 小时前
Nacos 源码深度畅游:Nacos 配置同步详解(下)
分布式·后端·github
方圆想当图灵4 小时前
Nacos 源码深度畅游:Nacos 配置同步详解(上)
分布式·后端·github