题目描述
输入格式
第一行有一个正整数 T(T <= 10),表示一共有 T 组数据。
接下来有 T 个 5×5 的矩阵,0
表示白色骑士,1
表示黑色骑士,*
表示空位。两组数据之间没有空行。
输出格式
对于每组数据都输出一行。如果能在 15 步以内(包括 15 步)到达目标状态,则输出步数,否则输出 -1
。
输入输出样例
输入 #1复制
2 10110 01*11 10111 01001 00000 01011 110*1 01110 01010 00100
输出 #1复制
7 -1
说明/提示
思路分析:
从题目表面意思可以看出题目是要我们从所给的一个状态经过最小步数来达到目标状态,本题如果采用bfs,则就是从空白开始出发,日字形走法向八个方向跟马交换,但是如果采用这样的走法我们发现每走一次就要去循环查看棋盘的状态是否符合目标状态,这样的时间复杂度我们是接受不了的。所以只能采用dfs进行搜索。
方法一:采用暴力dfs我们发现越往后分支越大,以至于大到无法控制,所以我们需要进行优化,本题则采用迭代加深逐层搜索,如果在本层达到目标状态,则停止后面一系列多余冗杂的搜索。
对于每增加一层去搜索,搜索次数都会成指数级别上升,对于有限的时间内我们对下次搜索设置一个门槛,满足某个条件才让其继续下一层的搜索,不能满足的说明其后面的搜索无意义(其步数过大,对于结果步数影响过大,搜索下去会超过15步或结果步数永远不会是最优)。
这一个门槛我们就采用了A*算法,即估价函数的意思,所谓的估价函数就是我们对于当前状态转换到目标状态所需的最理想步数,由此我们得知当前所用步数+估价函数算出的理想步数<=当前层数(当前限制的最大步数)。
方法二(推荐):采用双端dfs,因为题目限制最大修改步数是15,分为前一半和后一半,分开进行搜索,如果前一半找到目标状态,则不用对下一半展开搜索。如果前一半未达到目标状态,对于下一半的搜索我们为了避免分支过大,搜索量太大,则逆向思维从后往前搜(从目标状态往回推),对于前一半的状态我们用hashmap存起来,如果逆行搜索达到某个状态和在hashmap中存在,则说明我们当前在后半部分搜索的步数+前7步(前半部分限制的最大步数)就是我们最终找到目标状态所用的总步数。
代码如下:
法一:
import java.io.*; public class 骑士精神 { static class InputReader { BufferedReader br; public InputReader(InputStream stream) { br = new BufferedReader(new InputStreamReader(stream)); } public int nextIn