如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出
输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
基本思想在于:
使用bfs广度搜索,借用队列实现。
1)使用queue保存当前可能移动的所有状态
2)依次出队列再继续判断接下来的所有可能状态,插入队列
3) 对待每次的变化后的String,都需要保存当前的移动步数,这里用hashmap实现,每个键String 对应 一个值Integer(这个字符串的步数)
4)判断每一条变化的String是否与结果一致,若一致,则输出结果,否则继续
5)若直到最后的队列为空都没有结果,则输出-1
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str1 = sc.nextLine();
String str2 = sc.nextLine();
int result = -1;
HashMap<String, Integer> map = new HashMap<String,Integer>(); //用来存放移动的每一次String,以及当前步数,能够用来查重
Queue<String> queue = new LinkedList<String>(); //通过Queue实现广度遍历,使得存储的顺序是相邻的可移动方式
map.put(str1, 0);
queue.offer(str1);
int[] move = {-3,+3,-1,1}; //九宫格中所有的移动方式
while(result==-1) {
str1 = queue.poll();if(null==str1) break;
int temp = str1.indexOf("."); //获取当前队列中String的“.”的位置
for(int i=0;i<=3;i++) {
int p = temp+move[i];//计算移动的步数
if((p==2&&temp==3)||(p==3&&temp==2)||(p==5&&temp==6)||(p==6&&temp==5)) continue; //排除012345678的九宫格中 3和2;5和6的错误移动
if(p>=0&&p<=8) { //判断移动是否超出边界
String change = str1;
char temp_char = change.charAt(p);
change = change.replace('.', '0');
change = change.replace(change.charAt(p), '.');
change = change.replace('0',temp_char);
//以上是移动一次的结果
if(change.equals(str2)) { //判断是否相同,若相同,则返回结果
result = map.get(str1)+1;
}
if(!map.containsKey(change)) { //判断map中是否已经存在这个字符串,若没有,则存入
map.put(change, map.get(str1)+1);
queue.offer(change);
}
}
}
}
System.out.println(result);
}
}