九宫重排java

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

《九宫重排java》
《九宫重排java》

  我们把第一个图的局面记为:12345678.

  把第二个图的局面记为:123.46758

  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。

  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。 输入格式   输入第一行包含九宫的初态,第二行包含九宫的终态。 输出格式   输出最少的步数,如果不存在方案,则输出-1。 样例输入 12345678.

123.46758 样例输出 3 样例输入 13524678.

46758123. 样例输出 22

题解:
1.刚看到这道题,感觉可以用dfs,写了代码之后发现有一个问题,搜索的终点是什么?所以dfs只能预估最大步数max,然后搜索,但是是盲目得搜索到最大步数max,复杂度非常高。
2.后来改用bfs,每次走一步,将所有的状态记录下来,如果这种状态之前出现过,就放弃这条搜索路径,直到找到最终的状态。这种做法虽然较dfs有优化,但是大部分的搜索路径依然是盲目的。
3.最后看了别人的一些博客,发现这题可以用A*算法,关于A*算法怎么做,在这里就不说了,虽然想法比较简单,但是实现起来比较复杂,在这里就不说了。 4.下面给出bfs方法的java代码:

package 真题;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class 九宫重排精简版 {
	public static void main(String[] args) {
		Palace palace = new Palace();
	}
}
class Palace{
	String start;//初始字符串
	String end;//目标字符串
	int result=-1;//最终结果
	public Palace(){
		Scanner sca = new Scanner(System.in);
		start = sca.next();
		end = sca.next();
		HashSet<String> query = new HashSet<>();//hashSet用于快速查找
		HashMap<String, Integer> memery = new HashMap<>();//用于保存之前状态,key代表状态字符串,value代表到key状态所用的最小步数
		Queue<String> process = new LinkedList<String>();//bfs用到的队列
		memery.put(start,0);//放入初始字符串
		query.add(start);
		process.offer(start);//放入初始字符串
		while(result==-1){//当没有搜索到结果是继续搜索
			String cur = process.poll();
			int tmp = 0;
			while(cur.charAt(tmp)!='.'){
				tmp++;
			}
			int[] d = {-3,3,-1,1};//方向数组,分别表示上下左右
			for(int i=0;i<4;i++){
				int p = tmp+d[i];
				if(!(p<0||p>8||(p%3!=tmp%3&&p/3!=tmp/3))){
					String change = cur.replace('.', '*');//交换String中的两个字符,借助中间字符‘*’
					change = change.replace(cur.charAt(p),'.');
					change = change.replace('*',cur.charAt(p));
					if(change.equals(end)){//找到了目标状态
						result = memery.get(cur)+1;
					}
					if(!query.contains(change)){//如果之前没有这种状态
						query.add(change);
						memery.put(change,memery.get(cur)+1);
						process.add(change);//存入队列
					}
				}
			}
		}
		System.out.println(result);
	}
}

以上是第一次的代码,过了60分,然后对其进行了一些代码上的优化,最终100:
《九宫重排java》

优化的内容: 1.对hashmap进行了预容量设置 2.去掉hashset 3.对if语句进行优化(对于越行问题,只会出现在2–>3,3–>2,5–>6,6–>5这四组中,所以简化为p*tmp!=6&&p*tmp!=30即可) 以下是最终代码:

package 真题;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class 九宫重排精简版 {
	public static void main(String[] args) {
		Palace palace = new Palace();
	}
}
class Palace{
	String start;//初始字符串
	String end;//目标字符串
	int result=-1;//最终结果
	public Palace(){
		Scanner sca = new Scanner(System.in);
		start = sca.next();
		end = sca.next();
//		HashSet<String> query = new HashSet<>(1000000);//hashSet用于快速查找
		HashMap<String, Integer> memery = new HashMap<>(100000);//用于保存之前状态,key代表状态字符串,value代表到key状态所用的最小步数
		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(cur.charAt(tmp)!='.'){
				tmp++;
			}
			int[] d = {-3,3,-1,1};//方向数组,分别表示上下左右
			for(int i=0;i<4;i++){
				int p = tmp+d[i];
				int chengji = tmp*p;
				if(p>-1&&p<9&&chengji!=6&&chengji!=30){//2-->3,3-->2,5-->6,6-->5跨行了,要去掉
					String change = cur;
					char c = cur.charAt(p);
					change = cur.replace('.', '*');//交换String中的两个字符,借助中间字符‘*’
					change = change.replace(c,'.');
					change = change.replace('*',c);
					if(change.equals(end)){//找到了目标状态
						result = memery.get(cur)+1;
					}
					if(!memery.containsKey(change)){//如果之前没有这种状态
						memery.put(change,memery.get(cur)+1);
						process.add(change);//存入队列
					}
				}
			}
		}
		System.out.println(result);
	}
}
    原文作者:九宫格问题
    原文地址: https://blog.csdn.net/qq_23044403/article/details/68951954
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞