问题描述:
如下面第一个图的九宫格中,放着 1~8
的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678. 把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。 输入格式
输入第一行包含九宫的初态,第二行包含九宫的终态。 输出格式 输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出
22
解题思路:
使用广度搜索,不断移动为空的格子。找到符合条件的字符串时就是最少的步骤。之所以是最少是因为BFS遍历的特性。
需要注意的是在遍历的过程中会出现重复的字符串,需要跳过,否则会超时。
代码实现:
package 历届试题;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Scanner;
public class Main {
static String star;
static String end;
static LinkedList<Move> list = new LinkedList<Move>(); //用于bfs的队列
static HashSet<String> set = new HashSet<String>();
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
star = scanner.next();
end = scanner.next();
System.out.println(bfs());
}
private static int bfs() {
int[] dx = {-1,0,1,0}; //上,左,下,右
int[] dy = {0,-1,0,1};
int sx = star.indexOf(".")/3; //寻找九宫格初始状态空格子的位置
int sy = star.indexOf(".")%3;
list.add(new Move(sx,sy,star,0));
while(!list.isEmpty()) {
Move move = list.pollFirst();
if(move.temp.equals(end)) { //达到了目标状态
return move.step;
}
for(int i=0; i<4; i++) {
int x = move.x + dx[i];
int y = move.y + dy[i];
if(x<3 && x>=0 && y<3 && y>=0) { //保证不出界
//将两个位置进行交换
String t = move.temp;
char c = t.charAt(x*3+y);
t = t.replace(c, '-');
t = t.replace('.', c);
t = t.replace('-', '.');
if(!set.contains(t)) { //为了提高效率,添加过的字符串进行跳过
list.add(new Move(x, y, t, move.step+1));
set.add(t);
}
}
}
}
return -1;
}
}
class Move {
int x; //x和y表示空格所在的坐标
int y;
String temp; //当前格子的状态
int step; //当前的步数
public Move(int x, int y, String temp, int step) {
super();
this.x = x;
this.y = y;
this.temp = temp;
this.step = step;
}
}
提交结果:
第二次提交是跳过重复字符串的优化,第一次是没跳过重复字符串的代码。可以一下内存消耗相差了四倍。