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 };

 

posted @ 2021-03-14 13:01  habibah_chang  阅读(78)  评论(0编辑  收藏  举报