java:九宫重排
题目
问题描述
如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出
22
https://blog.csdn.net/Fly_as_tadpole/article/details/86536539
https://baijiahao.baidu.com/s?id=1611209814188127596&wfr=spider&for=pc
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class 九宫重排 {
static String start=null;//初始字符串
static String end=null;//目标字符串
static int result=-1;//结果
public static int bfs(){
Scanner sc=new Scanner(System.in);
start=sc.next();
end=sc.next();
//memery用于保存之前的状态,key代表状态字符串,value代表到key状态所用的最小步数
HashMap<String,Integer> memery=new HashMap<String,Integer>(100000);
Queue<String> process=new LinkedList<String>();//bfs时用到的队列
memery.put(start, 0);//放入初始字符串
//System.out.println(memery);
process.offer(start);//放入初始化字符串 添加一个元素并返回true
//System.out.println(process);
while(result==-1){//当没有搜索到结果时继续搜索
//poll:移除并返问队列头部的元素
String cur=process.poll();//取到队首元素,并让其出队..最先插入的元素将是最先被删除的元素
//System.out.println(cur);
/*
* 例如输入,12345678. 输出123.46758
* 12345678.
* 12345.786
* 1234567.8
* 12.453786
* 1234.5786
* 1234.6758
*/
int tmp=0;
while(tmp<cur.length()){//找到空白块的位置
if(cur.charAt(tmp)=='.')break;
tmp++;
}
/*
* 当cur=12345678.
* temp=8;
*/
//System.out.println(tmp);
//不是很明白这个方向代表的意思
//我又仔细的看了一下方格图,1如果向下,就变成.231,移了三个,+3
//7向上,123.46758 变为123746.58,左移了三位,就代表-3
//-1,左移
//1右移
int[] d={-3,3,-1,1};//方向数组,分别表示上下左右
for(int i=0;i<4;i++){//对上下左右元素进行bfs
int p=tmp+d[i];
/*
* 当temp=8时,p=5,先进行遍历,先上移
*/
//System.out.println(p);
//System.out.println(p%3+" "+tmp%3);
//System.out.println(p/3+" "+tmp/3);
//就是说,p是加了方向之后,0,8是为了限制左移右移的格数,而%3(上移),/3是为了限制上移,下移的显示
if(!(p<0||p>8||(p%3!=tmp%3&&p/3!=tmp/3))){//不允许出现越行问题
char a=cur.charAt(p);
//例如.往上移,a就为6
//System.out.println(a);
//下面三步相当于转换的过程,可以参考,这样子写的特别好
String change=cur.replace('.','*');//让*当转换中间量
change=change.replace(a,'.');
change=change.replace('*',a);
//如果最后转换过来的和最终状态相等
if(change.equalsIgnoreCase(end))
result=memery.get(cur)+1;//memery.get(cur)+1 为从初始状态到目前状态所要走的步数
//因为memery是按照步骤来的,但从0开始,所以就是要加1
if(!memery.containsKey(change)){//如果之前没有这种状态,则将其存入memery
memery.put(change, memery.get(cur)+1);
process.add(change);
//System.out.println(memery+" "+process);
/*
* cur=12345678.
* p=5,a=6
* 上移,memery:{12345678.=0, 12345.786=1}
* process=[12345.786],他之前把那些字符串当一个整体,全部移除了
*下移,p=11,这个方向的移动,是在之前的tmp的基础上行的,不可以
*左移:p=7,可以,a=8
*memery:{12345678.=0, 1234567.8=1, 12345.786=1}
*process:[12345.786, 1234567.8]
*右移:p=9,不可以结束。
*
*此时:cur=12345.786 上移了
*tmp=5
*p=2,上移,
*memery:{12345678.=0, 1234567.8=1, 12345.786=1, 12.453786=2}
*process:[1234567.8, 12.453786]
*之后再进行方向的移动:
*memery:{1234.5786=2, 12345678.=0, 1234567.8=1, 12345.786=1, 12.453786=2}
*process:[1234567.8, 12.453786, 1234.5786]
*
*此时第一个数向左边换做完了,之后变为向第一个排,这就是广度优先遍历
*cur=1234567.8
*/
}
}
}
}
return result;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(bfs());
}
}