问题:
推箱子问题。
给定n*m二维数组:
- . -> 通路
- T -> 箱子目标位置
- B -> 箱子当前位置
- S -> 人当前位置
- # -> 障碍(墙)位置
人S去推箱子B,使得箱子到达目标位置T,箱子最少移动多少步?
Example 1: Input: grid = [["#","#","#","#","#","#"], ["#","T","#","#","#","#"], ["#",".",".","B",".","#"], ["#",".","#","#",".","#"], ["#",".",".",".","S","#"], ["#","#","#","#","#","#"]] Output: 3 Explanation: We return only the number of times the box is pushed. Example 2: Input: grid = [["#","#","#","#","#","#"], ["#","T","#","#","#","#"], ["#",".",".","B",".","#"], ["#","#","#","#",".","#"], ["#",".",".",".","S","#"], ["#","#","#","#","#","#"]] Output: -1 Example 3: Input: grid = [["#","#","#","#","#","#"], ["#","T",".",".","#","#"], ["#",".","#","B",".","#"], ["#",".",".",".",".","#"], ["#",".",".",".","S","#"], ["#","#","#","#","#","#"]] Output: 5 Explanation: push the box down, left, left, up and up. Example 4: Input: grid = [["#","#","#","#","#","#","#"], ["#","S","#",".","B","T","#"], ["#","#","#","#","#","#","#"]] Output: -1 Constraints: m == grid.length n == grid[i].length 1 <= m <= 20 1 <= n <= 20 grid contains only characters '.', '#', 'S' , 'T', or 'B'. There is only one character 'S', 'B' and 'T' in the grid.
example 1:
解法:BFS + priority_queue
- 状态:(保存在visited中,防止重复。)
- 人的位置
- 箱子的位置
- queue中需要信息:
- 状态
- 当前箱子移动了多少步
- 决定是否先选择这个状态进行转移:权值
- 当前箱子 距 目标 的绝对距离 + 已经移动的步数。
- 值越小,越优先处理。
- 选择:
- 人移动:四个方向
- 对于当前状态的处理:
- 若当前box的位置==target的位置,返回当前步数moves。
- 人移动4个方向:(不能出界or碰到墙)
- 移动后,人==箱子 的位置,
- 那么箱子被推动,向人移动的同一方向(不能出界or碰到墙)
- 这时得到 新的人的位置np + 箱子位置nb -> 新状态,若visited中不存在,可以入队。
- 入队内容:
- 新状态:新的人的位置np + 箱子位置nb
- 当前箱子移动了多少步:当前步数+1
- 权值:新箱子nb到target的距离 + 当前步数+1
- 移动后,人!=箱子 的位置,
- 那么只有人移动,箱子不动
- 这时得到 新的人的位置np + 原箱子位置box -> 新状态,若visited中不存在,可以入队。
- 入队内容:
- 新状态:新的人的位置np + 原箱子位置box
- 当前箱子移动了多少步:当前步数(不变)
- 权值:原来权值(原箱子box到target的距离 + 当前步数)(不变)
- 移动后,人==箱子 的位置,
代码参考:
1 class cmp { 2 public: 3 bool operator()(const array<int,4>& a, const array<int,4>& b) { 4 return a[0]>b[0];//10,9,8...1 return 1 5 } 6 }; 7 class Solution { 8 public: 9 //权值degree:箱子距离目标的距离dist+箱子移动过的步数 10 //优先尝试上述权值较小的。->优先队列 11 //状态:人的位置 & 箱子的位置 12 //选择:人移动:上下左右四个方向 13 int MASK = 20;//20 14 int dir[5] = {1,0,-1,0,1}; 15 vector<int> target; 16 int n,m; 17 int dist(vector<int>& box) { 18 return abs(box[0]-target[0]) + abs(box[1]-target[1]); 19 } 20 int pos(vector<int>& p) { 21 return p[0]*MASK+p[1]; 22 } 23 string toString(int a, int b) { 24 return ::to_string(a)+ "_" + ::to_string(b); 25 } 26 int minPushBox(vector<vector<char>>& grid) { 27 vector<int> box; 28 vector<int> person; 29 int moves = 0; 30 n=grid.size(); 31 m=grid[0].size(); 32 priority_queue<array<int,4>, vector<array<int,4>>, cmp> q; 33 //degree, box_moves, person, box 34 //默认最大堆,less:从小到大排序,返回最后一个数(最大值) 函数体:return para_1 < para_2 35 // greater:从大到小排序,返回最后一个数(最小值) 函数体:return para_1 > para_2 36 unordered_set<string> visited;//person:x*20+y, box:x*20+y 37 //initialize: 38 for(int i=0; i<n; i++) { 39 for(int j=0; j<m; j++) { 40 if(grid[i][j]=='T') target={i,j}; 41 else if(grid[i][j]=='B') box={i,j}; 42 else if(grid[i][j]=='S') person={i,j}; 43 } 44 } 45 q.push({dist(box)+0, moves, pos(person), pos(box)}); 46 //visited.insert(toString(pos(person),pos(box))); 47 //loop 48 while(!q.empty()) { 49 auto [cur_degree, cur_moves, pp, pb] = q.top(); 50 person = {pp/MASK, pp%MASK}; 51 box = {pb/MASK, pb%MASK}; 52 q.pop(); 53 if(box[0]==target[0] && box[1]==target[1]) return cur_moves; 54 if(!visited.insert(toString(pp, pb)).second) continue; 55 for(int d=1; d<5; d++) { 56 vector<int> np = {person[0]+dir[d-1], person[1]+dir[d]}; 57 if(np[0]<0 || np[1]<0 || np[0]>=n || np[1]>=m 58 || grid[np[0]][np[1]]=='#') continue; 59 if(np[0]==box[0] && np[1]==box[1]) {//POS(person) == POS(box) 60 vector<int> nb = {box[0]+dir[d-1], box[1]+dir[d]};//box按照同样的方向移动一位 61 if(nb[0]<0 || nb[1]<0 || nb[0]>=n || nb[1]>=m 62 || grid[nb[0]][nb[1]]=='#') continue; 63 //if(visited.insert(toString(pos(np), pos(nb))).second) { 64 q.push({dist(nb)+cur_moves+1, cur_moves+1, pos(np), pos(nb)}); 65 // } 66 } else {//box 不动 67 //if(visited.insert(toString(pos(np), pos(box))).second) { 68 q.push({cur_degree, cur_moves, pos(np), pos(box)}); 69 //} 70 } 71 } 72 } 73 return -1; 74 } 75 };