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)
- 当前水平H:蛇尾(x,y) 蛇头(x,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)
- 当前水平H:蛇尾(x,y) 蛇头(x,y+1)
- 旋转:下一个状态的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:蛇尾(x,y) 蛇头(x,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 };