java:九宫重排(搜索)

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());
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向上Claire

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值