zoukankan      html  css  js  c++  java
  • 1210. Minimum Moves to Reach Target with Rotations

    问题:

    给定由0和1构成的n*n二维数组,表示迷宫。

    0代表通路,1代表障碍。

    长度为2的蛇,

    初始状态在第一行的前两个格子(0,0)<蛇尾>(0,1)<蛇头>

    最终要到达最后一行的最后两个格子(n-1,n-2)<蛇尾>(n-1,n-1)<蛇头>

    求最少走多少步能到。

    移动选项:

    • 向右移动一格:蛇头蛇尾 x不变,y+1
    • 向下移动一格:蛇头蛇尾 x+1,y不变
    • 旋转:
      • 条件:除了移动前后的cell都非障碍1外,还需corner cell也非 1。(如图:右下角cell)
      • 蛇的状态:水平->垂直:蛇尾不变,蛇头x+1,y-1
      • 蛇的状态:垂直->水平:蛇尾不变,蛇头x-1,y+1

     解法:BFS

    状态:蛇尾坐标(x,y)+蛇状态(H)(true:水平  or  false:垂直);即可确定蛇头蛇尾。

    • queue.push {x, y, H}
    • visited->grid记录
      • bit 0: block or route
      • bit 1: 水平状态visited
      • bit 2: 垂直状态visited
    • stp记录展开层数。

    每次处理一个状态node:

    若(x,y)=(n-1,n-2) && H==true ->target状态,返回stp

    获得当前状态的水平垂直mask:maskHV=1<<(H?1:2);

    判断下一个位置状态是否visited:

    • 向右移动:gird[x][y+1] 的【H】状态:gird[x][y+1]&maskHV==1?
    • 向下移动:gird[x+1][y] 的【H】状态:gird[x+1][y]&maskHV==1?
    • 旋转:gird[x][y] 的【非H】状态:gird[x][y]&(maskHV=1<<(H?2:1))==1?

    上述为非visited的情况下,看下一个移动是否合法:

    • 向右移动:下一个状态的cell都在坐标范围内,且都 grid & 1==0:
      • 当前水平H:蛇尾(x,y) 蛇头(x,y+1)
        • 蛇尾:(x,y+1)
        • 蛇头:(x,y+1+1)
      • 当前垂直~H:蛇尾(x,y) 蛇头(x+1,y)
        • 蛇尾:(x,y+1)
        • 蛇头:(x+1,y+1)
    • 向下移动:下一个状态的cell都在坐标范围内,且都 grid & 1==0:
      • 当前水平H:蛇尾(x,y) 蛇头(x,y+1)
        • 蛇尾:(x+1,y)
        • 蛇头:(x+1,y+1)
      • 当前垂直~H:蛇尾(x,y) 蛇头(x+1,y)
        • 蛇尾:(x+1,y)
        • 蛇头:(x+1+1,y)
    • 旋转:下一个状态的cell都在坐标范围内,且都 grid & 1==0,且corner grid[x+1][y+1] &1==0:
      • 当前水平H:蛇尾(x,y) 蛇头(x,y+1)
        • 蛇尾:(x,y)(不动)
        • 蛇头:(x+1,y+1-1)
      • 当前垂直~H:蛇尾(x,y) 蛇头(x+1,y)
        • 蛇尾:(x,y)(不动)
        • 蛇头:(x+1-1,y+1)

    ⚠️ 注意:水平垂直状态的转换:H?false:true

    代码参考:

     1 class Solution {
     2 public:
     3     int n;
     4     //remember [tail] to mark position
     5     //tail: x,y
     6     //head: if(horizontal--) x,y+1
     7     //      if(vertical || ) x+1,y
     8     //MOVE ->: tail: x, y+1; HV: not change
     9     //          precondition: H: (y+1),y+2<n; tail,head: grid[x][(y+1),y+2]==0
    10     //                        V: y+1<n; tail:grid[x][y+1]==0; head:grid[x+1][y+1]==0
    11     //MOVE ↓:  tail: x+1, y; HV: not change
    12     //          precondition: H: x+1<n; tail:grid[x+1][y]==0; head:grid[x+1][y+1]==0
    13     //                        V: (x+1),x+2<n; tail:grid[(x+1),x+2][y]==0;
    14     //ROTATE:  tail: x, y; HV: ~HV(T->F,F->T)
    15     //        precondition: H:x+1<n; head: grid[x+1][y]==0; corner: grid[x+1][y+1]==0
    16     //         ↓            V:y+1<n; head: grid[x][y+1]==0; corner: grid[x+1][y+1]==0
    17     //        H&V combination: x+1<n && y+1<n
    18     //                       && grid[x+1][y]==0 && grid[x][y+1]==0 && corner: grid[x+1][y+1]==0
    19     //queue cell: {tail[0],tail[1],hori?vert?}
    20     //visited:MARK grid-> bit_0 (1<<0): block or not
    21     //                    bit_1 (1<<1): H:visited
    22     //                    bit_2 (1<<2): V:visited
    23     bool canGoRight(vector<vector<int>>& grid, int x, int y, int H) {
    24         //cout<<"Goright"<<endl;
    25         if(H) return y+2<n && (grid[x][y+2]&1)==0;
    26         return y+1<n && (grid[x][y+1]&1)==0 && (grid[x+1][y+1]&1)==0;
    27     }
    28     bool canGoDown(vector<vector<int>>& grid, int x, int y, int H) {
    29         //cout<<"canGoDown"<<endl;
    30         if(H) return x+1<n && (grid[x+1][y]&1)==0 && (grid[x+1][y+1]&1)==0;
    31         return x+2<n && (grid[x+2][y]&1)==0;
    32     }
    33     bool canRotate(vector<vector<int>>& grid, int x, int y) {
    34         //cout<<"canRotate"<<endl;
    35         return x+1<n && y+1<n &&
    36             (grid[x+1][y]&1)==0 && (grid[x][y+1]&1)==0 && (grid[x+1][y+1]&1)==0;
    37     }
    38     int minimumMoves(vector<vector<int>>& grid) {
    39         n = grid.size();
    40         queue<array<int,3>> q;
    41         q.push({0,0,true});//source: --
    42         grid[0][0]|=(1<<1);
    43         int stp = 0;
    44         int maskHV;
    45         while(!q.empty()) {
    46             int sz = q.size();
    47             for(int i=0; i<sz; i++) {
    48                 auto [x,y,H] = q.front();
    49                 q.pop();
    50                 if(x==n-1 && y==n-2 && H) return stp;//target: --
    51                 maskHV = 1<<(H?1:2);
    52                 //cout<<"pop:[x,y,H]:"<<x<<","<<y<<","<<H<<",maskHV:"<<maskHV<<endl;
    53                 //cout<<((grid[x][y+1]&maskHV==0))<<endl;
    54                 if(y+1<n && (grid[x][y+1]&maskHV)==0//->
    55                    && canGoRight(grid, x, y, H)) {
    56                     //cout<<"R push:[x,y,H]:"<<x<<","<<y+1<<","<<H<<endl;
    57                     q.push({x,y+1,H});
    58                     grid[x][y+1]|=maskHV;
    59                 }
    60                 if(x+1<n && (grid[x+1][y]&maskHV)==0//
    61                    && canGoDown(grid, x, y, H)) {
    62                     //cout<<"D push:[x,y,H]:"<<x+1<<","<<y<<","<<H<<endl;
    63                     q.push({x+1,y,H});
    64                     grid[x+1][y]|=maskHV;
    65                 }
    66                 maskHV = 1<<(H?2:1);
    67                 if((grid[x][y]&maskHV)==0
    68                   && canRotate(grid,x,y)) {
    69                     //cout<<"RO push:[x,y,H]:"<<x<<","<<y<<","<<~H<<endl;
    70                     q.push({x,y,H?false:true});
    71                     grid[x][y]|=maskHV;
    72                 }
    73             }
    74             stp++;
    75         }
    76         return -1;
    77     }
    78 };
  • 相关阅读:
    python找出数组中第二大的数
    【高并发解决方案】5、如何设计一个秒杀系统
    如何找出单链表中的倒数第k个元素
    二叉树的前序,中序,后序遍历
    剑指Offer题解(Python版)
    python之gunicorn的配置
    python3实现字符串的全排列的方法(无重复字符)
    python实现斐波那契数列
    每天一个linux命令(56):netstat命令
    每天一个linux命令(55):traceroute命令
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/14532160.html
Copyright © 2011-2022 走看看