第四届蓝桥杯Java B组决赛 九宫重排

1. 题意

标题:九宫重排

如图1的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成图2所示的局面。
我们把图1的局面记为:12345678.
在这里插入图片描述
把图2的局面记为:123.46758
在这里插入图片描述
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。

例如:
输入数据为:
12345678.
123.46758
则,程序应该输出:
3

再如:
输入:
13524678.
46758123.
则,程序输出:
22

2. 分析

可以把空白格当成一个小人,然后向上下左右移动(移动后与元素交换位置),看是否能达到终态。

使用BFS,每次移动后,保存当前状态,与终态比较,是否一致,如果一致就输出步数

我们需要将走过的状态存到set中,不能重复走

3. 代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.HashSet;

public class Main{
    static String start, end;
    static int[] move = {-3, 3, -1, 1}; // 上下左右
    static HashSet<String> hs = new HashSet<String>();
    
    static class Board {
        String chess; // 棋盘状态
        int pos; // 坐标
        int cnt; // 步数
        public Board(String chess, int pos, int cnt) {
            this.chess = chess;
            this.pos = pos;
            this.cnt = cnt;
        }
    }
    
    // 交换下标a b的两个字符
    static String swap(String s, int a, int b) {
       StringBuilder sb = new StringBuilder();
       for (int i = 0; i < s.length(); i++) {
           if (i == a) {
               sb.append(s.charAt(b));
           } else if (i == b) {
               sb.append(s.charAt(a));
           } else {
               sb.append(s.charAt(i));
           }
       }
       return sb.toString();
    }
        
    static void BFS(Board s) {
        ArrayDeque<Board> q = new ArrayDeque<>();
        q.offerLast(s);
        hs.add(s.chess);
        while(!q.isEmpty()) {
            Board e = q.removeFirst();
            if (e.chess.equals(end)) {
                System.out.println(e.cnt);
                return ;
            }
            
            for (int i = 0; i < 4; i++) {
                // 在边上的时候不能左右移动
                if ((e.pos == 3 || e.pos == 6) && i == 2) continue;
                if ((e.pos == 2 || e.pos == 5) && i == 3) continue;
                int pos = e.pos + move[i];
                if (pos >= 0 && pos < 9) {
                    int cnt = e.cnt + 1;
                    // 交换位置 e.pos, pos
                    String chess = swap(e.chess, e.pos, pos);
                    if (!hs.contains(chess)) {
                        hs.add(chess);
                        Board t = new Board(chess, pos, cnt);
                        q.offerLast(t);
                    }
                }
                
            }
        }
        System.out.println("-1");
    }
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        start = br.readLine();
        end = br.readLine();
        // 找到起点, 开始搜索
        for (int i = 0; i < start.length(); i++) {
            if (start.charAt(i) == '.') {
                String s = start;
                Board b = new Board(s, i, 0);
                BFS(b);
                break;
            }
        }
    }
}

可以将棋盘状态用一个大数字表示,将.号转换为0。
这样set判重速度会更快,但代码量会增加一些

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值