题解

题目难度:hard

知识点:迷宫搜索类问题,利用BFS找到最短路径。

分析:

将人所在位置与箱子所在位置以及所走步数看作整体,新建节点Node。首先初始位置入队,通过移动不断将还没有经过的下一位置节点入队,直至找到箱子之前箱子的位置是不变的;当人找到箱子之后(即在箱子的一侧,上下左右),开始推箱子往另一侧走(下上右左),此时人和箱子的位置都开始移动,直至走到终点或无路可走结束。
本题可以分为2个过程:(具体实现思想见代码中注释)
① 人在找到箱子之前单独移动,箱子原地不动;在这个过程中,人要从“S”走到箱子“0”的旁边(上下左右)。
② 人找到箱子之后和箱子一起向“另一侧”移动,..S0.. -> ...S0. 。

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {

    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        char[][] chas=new char[n][m];
        // 人的起始位置S 以及箱子的位置
        int startX=0,startY=0,boxX=0,boxY=0;
        // 判断位置 ,即人要先找到箱子,再推着箱子往前走
        for(int i=0;i<n;i++){   
            String string=sc.next();
            for(int j=0;j<m;j++){
                chas[i][j]=string.charAt(j);
                if(chas[i][j]=='S'){
                    startX=i;
                    startY=j;
                }
                if(chas[i][j]=='0'){
                    boxX=i;
                    boxY=j;
                }
            }
        }
        System.out.println(solve(chas,startX,startY,boxX,boxY));
    }

    public static class Node{
        int px;  // 人的位置
        int py;
        int bx;  //箱子的位置
        int by;
        int step;  //从初始位置到现在节点所走的步数
        public Node(int px,int py,int bx,int by){
            this.px=px;
            this.py=py;
            this.bx=bx;
            this.by=by;
        }
    }


    private static int solve(char[][] chas,int startX, int startY,int boxX,int boxY) {
        Node start=new Node(startX, startY,boxX,boxY);
        int n=chas.length;
        int m=chas[0].length;
        // iswalked四维数组,可以用来存储走过的路径以防重复。
        int[][][][] iswalked=new int[n][m][n][m];
        // 每个节点都有dir4个方向的移动,分别是  下右上左   
        int[][] movedir=new int[][]{{1,0},{0,1},{-1,0},{0,-1}};  

        Queue<Node> que=new LinkedList<>();  //利用队列实现BFS
        start.step=0;
        que.add(start);

        //开始BFS广度搜索最短路径
        while(!que.isEmpty()){
            Node cur=que.poll();
            int newBx=cur.bx;
            int newBy=cur.by;
            for(int i=0;i<4;i++){  // 向4个方向走

                //人在箱子左边或右边
                if(cur.px==cur.bx){

                     if (cur.py+movedir[i][1]==cur.by){
                         newBy = cur.by+movedir[i][1];
                     }else{
                         newBy = cur.by;
                     }

                }  

              //人在箱子上面或下面 
                if(cur.py==cur.by){
                    if(cur.px+movedir[i][0]==cur.bx){
                        newBx = cur.bx+movedir[i][0];
                    }else{
                        newBx = cur.bx;
                    }
               }


                // 箱子找到了要随人往4个方向动;没找到则箱子不动人动
                Node next=new Node(cur.px+movedir[i][0], cur.py+movedir[i][1],newBx,newBy); 
                //不能让人在没找到箱子之前出地图或者自己提前到目的地
                if(next.px<0||next.px>=n||next.py<0||next.py>=m||chas[next.px][next.py]=='#'   
                        ||next.bx<0||next.bx>=n||next.by<0||next.by>=m
                        ||chas[next.bx][next.by]=='#'){
                    continue;
                }

                // 0说明这条路径没有走过
                if(iswalked[next.px][next.py][next.bx][next.by]==0){  
                    iswalked[next.px][next.py][next.bx][next.by]=1;
                    next.step=cur.step+1;
                    if(chas[next.bx][next.by]=='E'){   //此时把箱子推到终点了
                        return next.step;  // 最先到终点的就是最短路径
                    }
                    que.add(next);
                }
            }
        }
        return -1;
    }


}