蓝桥杯java备赛Day3——跳马

蓝桥杯java备赛A组——跳马

问题描述

问题描述: 一个8×8的棋盘上有一个马初始位置为(a,b),他想跳到(c,d),问是否可以?如果可以,最少要跳几步?
输入格式: a,b,c,d
输出格式: 如果跳不到位置,则输出-1;否则输出最小步数。

问题解决思路

问题条件

  • 马走日字

问题转化

  • 这其实是一个寻找路径问题,可以采用BFS(广度优先搜索)或者DFS(深度优先搜索)实现,DFS适合寻找所有路径,BFS适合寻找最短路径,因此选择BFS。

DFS与BFS区别(寻找路径)

  • DFS适合寻找全部路径,BFS适合寻找最短路径。
  • DFS使用栈(先进后出),BFS使用对列(先进先出)。

问题思路

  • 从(a,b)开始,(a,b)入队,当(a,b)出队时,将符合"日"字的位置入队,循环步骤,直至到达(c,d)。
  • 每一个位置下一步最多有8个选择。
static int[][] ma = {{1,2},{-1,2},{1,-2},{-1,-2},{2,1},{-2,1},{2,-1},{-2,-1}};
  • 做多的步数不可能超过64.
  • 还需注意超出棋盘范围的位置不能走,也就是超出棋盘的位置不会加入队列,但为了方便确定下一步的开始,将出界位置的个数也都记录下来。
    需要解决的问题:
  • 如何确定现在该向下一步也就是在树结构中向下一层?
    • 若不考虑出界,则树的结构应该是每个节点(出最后一层之外)都有8个子节点,树的深度表示步数,一步代表一层,也就是说,第i层(从0开始),表示第i步,没有出界的位置个数+出界的位置个数=8^i,可以以这个为向下一层走的条件。
  • 如何确定跳不到目标位置?
    • 共有64个位置,依据可到达路径来说,不会有在一个位置出现两次的情况出现,那么就算每个位置都走一次,也才64次,因此说如果走了64步都没到达目标位置,那么就说明跳不到。
    • 或者是当队列为空时,说明已经没有路可走,那么也就说明跳不到。
      例图:
      请添加图片描述

完整代码

package AlgorithmPractice.Day8;

import java.util.Deque;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

/*问题描述:一个8×8的棋盘上有一个马初始位置为(a,b),他想跳到(c,d),问是否可以?如果可以,最少要跳几步?
* 输入格式:a,b,c,d
* 输出格式:若挑不到,输出-1;若跳的到,输出最少步数*/
public class Exercise3 {
    //走马时最多会有8个位置
    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 scan = new Scanner(System.in);
        int a = scan.nextInt();
        int b = scan.nextInt();
        int c = scan.nextInt();
        int d = scan.nextInt();
        bfs(a,b,c,d);
        scan.close();
    }
    public static void bfs(int a,int b,int c,int d){
        //对列,因为要存放的是坐标,因此对列元素是数组形式[x,y]
        Deque<int[]> queue = new LinkedList<>();
        int[] start = new int[]{a,b};
        queue.offer(start);
        //步数计数器
        int count = 0;
        //每一层放入队列的元素计数器
        int dequeCount = 0;
        //cant[i]表示第i步不能走的位置数
        int[] cant = new int[65];
        if(a==c&&b==d){
            System.out.println(count);
            return;
        }
        while (true){
            //走8步,但需要判断
            for(int[] i:ma){
                int[] temp = new int[2];
                temp[0] = queue.getFirst()[0] + i[0];
                temp[1] = queue.getFirst()[1] + i[1];
                //需要判断一下,移动后的坐标是否超出了方格范围
                if(temp[0]>0&&temp[0]<9&&temp[1]>0&&temp[1]<9){
                    //判断移动之后是否达到目的地
                    if(temp[0]==c&&temp[1]==d){
                        System.out.println(count+1);
                        return;
                    }else {
                        //将位置存入队列
                        queue.offer(temp);
                        dequeCount++;
                        //如果队列中除了初始位置,后面存放的个数已经到达的顶点,即要走第n步,该层元素中已有8^n个元素,则出队,进行下一步
                        if(Math.pow(8,count+1)==dequeCount+cant[count+1]){
                            count++;
                            cant[count+1] = 8*cant[count];
                            dequeCount = 0;
                        }
                    }
                }else {
                    cant[count+1]++;
                    if(Math.pow(8,count+1)==dequeCount+cant[count+1]){
                        count++;
                        cant[count+1] = 8*cant[count];
                        dequeCount = 0;
                    }
                }
            }
            //当前位置所有可能位置都已存进去,可以弹栈,进行下一步
            queue.pollFirst();
            if(count>64||queue.size()==0){
                System.out.println(-1);
                return;
            }
        }
    }
}

结果

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值