问题描述:
一个8×8的棋盘上有一个马初始位置为(a,b),他想跳到(c,d),问是否可以?如果可以,最少要跳几步?
输入格式:
如果跳不到,输出-1;否则输出最少跳到的步数。
输出格式:
1 1 2 3
样例输出:
1
数据规模和约定:
0<a,b,c,d≤8且都是整数。
思路:
跳马问题,我们首先想到的就是运用蓝桥杯中的暴力算法的模式,这里我使用bdf(宽度优先算法)
不了解的小伙伴可以看看这个视频了解了解:图Graph, 深度优先遍历(DFS), 广度优先遍历(BFS)【数据结构和算法入门9】_哔哩哔哩_bilibili (视频的17:05中有讲到)
首先让我们来了解跳马的一个原则,来上图咯!~~~~
相信大家都有了解过中国的象棋,根据马行日,我们可以建立如此的数学模型,假设此时马的坐标位置为x,y那么它可以走的位置有上图八种情况。
此时我们就可以把x和y八种不同的情况分别储存在一维数组中去。
int dx[] = new int[]{2, 1, 2, 1, -2, -1, -2, -1};
int dy[] = new int[]{1, 2, -1, -2, 1, 2, -1, -2};
说到暴力算法,这时为啥呢,还是回到上面的那张图,在第一层中,马可以走以上八个点,而八个点中的每一个点又可以有八个点,而当我们每遍历完一层,还没有找到目标点的情况下,那么这个时候就已经算上马走了一次了,(比如说马要达到n层才能达到那个点,现在第一层的所有可能都已经发生了,但是还没有到达,所以马就已经算上走了一步了,直到它走到n层中的某一个点时,循环就结束了,对于前面所走的点大家的机会都是公平的,因此最短路径的问题就完美解决了),那如果下一次跳就到达了目标的位置,我们可以知道才这一层中前面遍历过的点已经是和这个目标点是一致的基本次数都是一样,而下一步就到达目标位置则说明前面的所有出现的情况都是相同的,即使后面的尝试再次到达目标位置的话,都会使得跳到的次数比这次的还要来得多。
现在我们首先来看看部分代码:
Deque<int []> temp = new LinkedList<>();
temp.offer(new int[]{a,b});
if (a == c && b == d){
System.out.println(0);
}
while (true){
for (int i = 0; i < 8; i++){
int[] tempArr = new int[2];
tempArr[0] = temp.getFirst()[0] + dx[i];
tempArr[1] = temp.getFirst()[1] + dy[i];
if (tempArr[0] == c && tempArr[1] == d){
System.out.println(count1 + 1);
return;
}
temp.offer(tempArr);
count2++;
if (Math.pow(8,count1+1) == count2){
count1++;
}
}
temp.pollFirst();
}
bdf算法,我们这里使用Deque类,它主要是一个队列的类。这里我们主要知道它几个简单的方法即可。
offer():把元素入队 getFirst():取得队头的第一个元素 pollFirst();把队头的第一个元素弹出去
这里仅仅是本人的主观上的理解,想要更详细的了解还请看看以下链接:http://t.csdn.cn/TZgn6
而这里的代码和上面的思路相通,不懂的可以结合代码多理解理解上面的思路。补充一点:每当我们遍历完一层的时候就把刚开始的那个点(也就是队头元素弹出去)
完整代码展示:
import java.util.*;
/**
* @author Qik~
* @create 2023-01-16 19:37
*/
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int a = scan.nextInt();
int b = scan.nextInt();
int c = scan.nextInt();
int d = scan.nextInt();
//用来计算结果和判断该点是否测试完成八种情况的跳跃
int count1 = 0;
int count2 = 0;
//马儿可能跳跃的点的位置
int dx[] = new int[]{2, 1, 2, 1, -2, -1, -2, -1};
int dy[] = new int[]{1, 2, -1, -2, 1, 2, -1, -2};
Deque<int []> temp = new LinkedList<>();
temp.offer(new int[]{a,b});
if (a == c && b == d){
System.out.println(0);
return;
}
while (true){
for (int i = 0; i < 8; i++){
int[] tempArr = new int[2];
tempArr[0] = temp.getFirst()[0] + dx[i];
tempArr[1] = temp.getFirst()[1] + dy[i];
if (tempArr[0] == c && tempArr[1] == d){
System.out.println(count1 + 1);
return;
}
temp.offer(tempArr);
count2++;
if (Math.pow(8,count1+1) == count2){
count1++;
}
}
temp.pollFirst();
}
}
}