输入格式
一行四个数字a,b,c,d。
输出格式
如果跳不到,输出-1;否则输出最少跳到的步数。
核心思想:BFS算法(宽搜)
(不讲解bfs算法,大家可以去b站基本了解,有助于看懂下面的思想和代码)不怕你学不会系列:宽度优先搜索_哔哩哔哩_bilibili宽度优先搜索基本思想https://www.bilibili.com/video/BV1H44y1871A/?spm_id_from=autoNext 使用原因有二:
一:马有8步选择,不清楚第几步选择,第几次走8步可以到达目标值,所以本质上需要遍历所有结果,也就是要么bfs(深度搜索)要么bfs(宽度搜索)。前者适合解决的是所有路径,后者解决的则是最短路径,所以这里用bfs算法更好
二:使用的是队列,dfs算法用的是栈,bfs算法用的是队列,两者的区别就是后者是先进先出,那么,我根据当前遍历的值,比如说是(1,1)找到它下八个值之后,我就要把(1,1)弹出去,指针指向下一位(也即是(1,1)下八个值的第一个值,比如是(2,3))。这样保证我们能遍历完所有的值。
程序思想:
1.接受初始步a,b 终点步 c,d
2.判断a ,b 和c,d 是否相等。是就直接输出,螺旋上天。
3.bfs算法求解最短路径
3.1声明两个计数器,一个表示马真正走了多少步,一个表示队列存了多少种(未计算下一步的)坐标。
3.2循环,每次都拿队列第一个数来求出八种坐标,并且判断是否我们要的结果,是就步数计数器+1,直接返回,跳出循环。不是就把这个坐标存到队列中,以后还得拿来求它的下一八步嘞。存完之后,队列计数器也要加一,并且存完八个,队列第一个数就没用了,要弹出,给下一个数空间。
代码如下:
import java.util.Arrays;
import java.util.Deque;
import java.util.linkedList;
import java.util.Scanner;
public class Main01 {
//跳马问题
//BFS +算法
//八行两列的马步。
static int[][] ma = {{1,2},{-1,2},{1,-2},{-1,-2},{2,1},{-2,1},{2,-1},{-2,-1}};
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int a = in.nextInt();
int b = in.nextInt();
int c = in.nextInt();
int d = in.nextInt();
//ab,初始坐标。cd终点坐标。
tiaoma(a, b, c, d);
}
static void tiaoma(int a, int b,int c, int d){
//初始化队列
Deque B = new linkedList<>();
B.offer(new int[]{a,b});
//计数器
int cout = 0;
int incout =0;
//第0步
if (a == c && c == d) {
System.out.println(cout);
return;
}
//第n步
while (true)
{
for(int[] i : ma) {
//临时数组
int[] at = new int[2];
at[0] = B.getFirst()[0]+i[0];
at[1] = B.getFirst()[1]+i[1];
//如果是目标值,就直接返回
if(Arrays.toString(at).equals(Arrays.toString(new int[]{c, d}) )){
System.out.println(cout+1);
return;
}
//不是就存入.并且内部计数器+1
B.offer(at);
incout+=1;
//如果存入的数据够了,就让外部计数器+1
if (Math.pow(8,cout+1)==incout){
cout+=1;
}
} //循环一次之后,新八值就找到了,那么可以弹栈了
B.pollFirst();
}
}
}
结果(还是很美的)
(这里插几句,为什么不考虑负数的情况,不考虑出界的问题,emmm出界问题确实没考虑。负数的情况就是(1,1)下一步(-1,0)在棋盘上不存在,但是(-1,0)下一步(0,2)回来了,还跑到别的地方去了,那么这到底算可以还是不可以捏?其实你把棋盘化成坐标轴,你会发现它是对称的,也就是如果它真的能走回来,并且走到我们要的答案,那么一定也会有对称的,同样的步数,并且一直在棋盘内的走法,也能走到目标值,所以跑到外界去了,问题不大)
如图:



