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判重速度会更快,但代码量会增加一些