九宫重排java

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

  我们把第一个图的局面记为: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:

优化的内容:
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);
	}
}


  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值