一道bfs类型的算法问题。

先给出题目源地址:九宫重排

 

题目描述

如下面第一个图的九宫格中,放着  1~8  的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

java 制作九宫格图片 java九宫格算法_蓝桥杯

 

我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。

输入

输入第一行包含九宫的初态,第二行包含九宫的终态。 

输出

输出最少的步数,如果不存在方案,则输出-1。

样例输入


12345678. 123.46758


样例输出


3


思路:

通过看题,先了解到:

空格的四周字符可以和它交换,即:

java 制作九宫格图片 java九宫格算法_算法_02

 

题目要求能到达目标图形的最少步数,我想到了dfs和bfs,我上网看了一些大佬的回答:如果使用dfs太过于盲目,一条路走到黑,很容易出现超时现象,相比较而言,用bfs一层一层的走,将每一步都记录下来,然后找到最短路径。bfs想对于dfs而言约束条件更多一些,也就更稳更快。

在程序中要注意几个问题:

1、我们要声明一个表memery来保存之前的状态

2、由于采用了bfs,那么应当是第一次能到达目标状态时,就是最少步数

3、我们要注意越行问题,我们可以用d = {-3,3,-1,1}方向数组,分别表示上下左右,让空格的位置数加上数组中相应的数即可得到要移动到下一步数的位置,但是有时会出现越行问题,比如3-1=2,3的左边本没有数,但是一相减却让下一步跑到了上一行的末尾,这是不行的,下一步的位置只能是和空格在同一行或同一列, 所以需要给出约束条件,本代码中给出:

!(p<0||p>8||(p%3!=tmp%3&&p/3!=tmp/3)),其中p为下一步位置,tmp为空格位置

代码:

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 scan = new Scanner(System.in);
		start = scan.next();
		end = scan.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); //放入初始字符串
		process.offer(start); //放入初始化字符串
		
		while(result == -1){//当没有搜索到结果是继续搜索
			String cur = process.poll(); //取到队首元素,并让其出队
			int tmp = 0;
			while(tmp<cur.length()){//找到空白块的位置
				if(cur.charAt(tmp)=='.')break;
				tmp++;
			}
			int[] d = {-3,3,-1,1};//方向数组,分别表示上下左右
			for(int i=0; i<4; i++){//对上下左右元素进行bfs
				int p = tmp + d[i];
				if(!(p<0||p>8||(p%3!=tmp%3&&p/3!=tmp/3))){//不允许出现越行问题
					char a = cur.charAt(p);
					String change = cur.replace('.', '*'); //让*当转换中间量
					change = change.replace(a, '.');
					change = change.replace('*', a);
					
					if(change.equals(end)){
						result = memery.get(cur)+1;//memery.get(cur)+1 为从初始状态到目前状态所要走的步数
					}
					if(!memery.containsKey(change)){//如果之前没有这种状态,则将其存入memery
						memery.put(change, memery.get(cur)+1); 
						process.add(change);
					}
				}
			}
		}
		
		return result;
	}
	public static void main(String[] args) {
		System.out.println(bfs());
	}

}