我好像逃却逃不掉 | 豆包MarsCode AI刷题

155 阅读4分钟

题目描述

曾经的我不过是一介草民,混迹市井,默默无名。直到我被罗马的士兵从家乡捉走丢进竞技场....

对手出现了,我架紧盾牌想要防御,只觉得巨大的冲击力有如一面城墙冲涌而来,击碎了我的盾牌,我两眼发昏,沉重的身躯轰然倒地。
—— 我好想逃
但罗马最大的竞技场,哪有这么容易逃得掉。工程师们早就在地上装了传送机关,虽不会伤人,却会将站在上面的人传到它指向的位置。若是几个传送机关围成一个环,不小心踩在上面的人就会被一圈圈的反复传送...
想到这里,我不由得打了个寒颤。必须避开这些危险的地方!

输入格式

  • 第一行输入两个整数 n 和 m,表示迷宫的长和宽

  • 接下来 n 行,每行 m 个字符,用于描述迷宫构造,每个字符可能为以下几种

    • . (小数点)表示空地,玩家在空地时可以选择往 [上,下,左,右] 中的某个方向移动一格

    • UDLR 分别表示朝向 [上,下,左,右] 的传送带,站在传送带上的人会被强制移动到其指向的下一个位置

      • 如果下一个位置还是传送带,会被继续传下去
      • 如果传送带指向迷宫外,玩家会撞在墙上昏过去,游戏结束,无法再到达出口
    • O 表示迷宫出口

输出格式

  • 输出一个数字,表示迷宫中有多少个位置,当玩家移动到此处时,无论接下来如何移动都无法再到达出口。
    (传送带、空地、出口都算一个位置)

输入样例

5 5  
.....  
.RRD.  
.U.DR  
.ULL.  
....O

输出样例

10

数据范围

  • 1≤n,m≤1051≤n,m≤105
  • 1≤n⋅m≤1051≤n⋅m≤105
  • 保证每个迷宫中有且仅有一个出口

思路

定义两个二维数组:

    static int[][] flag;//是否可达
    static int[][] used;//是否遍历过

找到O出口位置portX和portY

 for(int i=0;i<N;i++){
      for(int j=0;j<M;j++){
           if(data[i][j]=='O'){
                  portX=i;
                  portY=j;
                  break;
                }
         }
   }

出口处DFS遍历data迷宫,遇到一个可达位置,flag置为1,继续向上下左右位置判断是否可达

private static void traverse(int x,int y,char[][] data){
        if(x<0||y<0||x>=data.length||y>=data[0].length){
            return;
        }
        if(used[x][y]==1){
            return;
        }
        used[x][y]=1;//标记为访问过
        flag[x][y]=1;//标记为可达
        //找到一个可达地点,继续向上下左右判断是否可达
        //向上判断
        if(x-1>=0&&(data[x-1][y]=='D'||data[x-1][y]=='.')){//向上判断时该处是向下,说明也是可达,下左右以此类推
            traverse(x-1,y,data);
        }
        //向下判断
        if(x+1< data.length&&(data[x+1][y]=='U'||data[x+1][y]=='.')){
            traverse(x+1,y,data);
        }
        //向左判断
        if(y-1>=0&&(data[x][y-1]=='R'||data[x][y-1]=='.')){
            traverse(x,y-1,data);
        }
        //向右判断
        if(y+1<data[0].length&&(data[x][y+1]=='L'||data[x][y+1]=='.')){
            traverse(x,y+1,data);
        }
    }

最后统计所有flag=0的不可达位置,完整代码如下:


public class Main {
   static int[][] flag;//是否可达
   static int[][] used;//是否遍历过
   public static int solution(int N, int M, char[][] data) {
       // Edit your code here
       int portX=0,portY=0;
       flag = new int[N][M];
       used = new int[N][M];
       for(int i=0;i<N;i++){
           for(int j=0;j<M;j++){
               if(data[i][j]=='O'){
                   portX=i;
                   portY=j;
                   break;
               }
           }
       }
       flag[portX][portY]=1;
       traverse(portX,portY,data);
       int result=0;
       for(int i=0;i<N;i++){
           for(int j=0;j<M;j++){
               if(flag[i][j]==0){
                   result++;
               }
           }
       }
       return result;
   }
   private static void traverse(int x,int y,char[][] data){
       if(x<0||y<0||x>=data.length||y>=data[0].length){
           return;
       }
       if(used[x][y]==1){
           return;
       }
       used[x][y]=1;//标记为访问过
       flag[x][y]=1;//标记为可达
       //找到一个可达地点,继续向上下左右判断是否可达
       //向上判断
       if(x-1>=0&&(data[x-1][y]=='D'||data[x-1][y]=='.')){
           traverse(x-1,y,data);
       }
       //向下判断
       if(x+1< data.length&&(data[x+1][y]=='U'||data[x+1][y]=='.')){
           traverse(x+1,y,data);
       }
       //向左判断
       if(y-1>=0&&(data[x][y-1]=='R'||data[x][y-1]=='.')){
           traverse(x,y-1,data);
       }
       //向右判断
       if(y+1<data[0].length&&(data[x][y+1]=='L'||data[x][y+1]=='.')){
           traverse(x,y+1,data);
       }
   }

   public static void main(String[] args) {
       // Add your test cases here
       char[][] pattern = {
       {'.',  '.', '.', '.', '.'},
       {'.',  'R', 'R', 'D', '.'},
       {'.', 'U', '.', 'D', 'R'},
       {'.', 'U', 'L', 'L', '.'},
       {'.', '.', '.', '.', 'O'}
   };
       System.out.println(solution(5, 5, pattern) == 10);
   }
}

本题关键点:找到一个可达位置时,再向上判断,如果上面的位置是D(向下),说明上面的位置也是可达的,则继续向上递归;如果下面的位置是U,说明下面的位置也是可达的.....