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();
    }
}
相关推荐
向前看-2 小时前
验证码机制
前端·后端
超爱吃士力架4 小时前
邀请逻辑
java·linux·后端
AskHarries6 小时前
Spring Cloud OpenFeign快速入门demo
spring boot·后端
isolusion7 小时前
Springboot的创建方式
java·spring boot·后端
zjw_rp7 小时前
Spring-AOP
java·后端·spring·spring-aop
TodoCoder8 小时前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
凌虚8 小时前
Kubernetes APF(API 优先级和公平调度)简介
后端·程序员·kubernetes
机器之心9 小时前
图学习新突破:一个统一框架连接空域和频域
人工智能·后端
.生产的驴10 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
顽疲10 小时前
springboot vue 会员收银系统 含源码 开发流程
vue.js·spring boot·后端