LC 1263. 推箱子
题目:推箱子中箱子的最少移动步数,人的次数不算
方法一:优先队列+BFS
Node{步数,人x,人y,箱子x,箱子y},优先队列按步数从小到大排序,每次取最小的出来更新(相当于Dijkstra变形),vis记录节点是否访问。
也可以完全用dis数据,记录达到某状态的最小距离,按dis更新,那就是完全Dijkstra了
人移动可以推箱子,也可能不推,判断一下,没有推箱子的话步数不变。
class Solution {
public:
bool vis[25][25][25][25];
const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
int minPushBox(vector<vector<char>>& grid) {
memset(vis, 0, sizeof(vis));
priority_queue<vector<int>, vector<vector<int>>, greater<vector<int>>> pq; // 取步数最小的
int row = grid.size(), col = grid[0].size();
int ax, ay, bx, by, ex, ey;
for(int i = 0;i < row;i++) {
for(int j = 0;j < col;j++) {
if(grid[i][j] == 'S') {
ax = i, ay = j;
grid[i][j] = '.';
}
if(grid[i][j] == 'B') {
bx = i, by = j;
grid[i][j] = '.';
}
if(grid[i][j] == 'T') {
ex = i, ey = j;
}
}
}
pq.push({0, ax, ay, bx, by}); // 步数,人,箱子
vis[ax][ay][bx][by] = true;
while(!pq.empty()) {
auto p = pq.top();pq.pop();
// cout << p[0] << " " << p[1] << " " << p[2] << " " << p[3] << " " << p[4] << endl;
if(p[3] == ex && p[4] == ey) return p[0];
for(int i = 0;i < 4;i++) {
int nax = p[1]+dx[i], nay = p[2]+dy[i]; // 人
if(nax < 0 || nax >= row || nay < 0 || nay >= col || grid[nax][nay] == '#') continue;
int nbx = (nax == p[3] && nay == p[4] ? p[3]+dx[i] : p[3]); // 箱子要么随人走,要么不动
int nby = (nax == p[3] && nay == p[4] ? p[4]+dy[i] : p[4]);
if(nbx < 0 || nbx >= row || nby < 0 || nby >= col || grid[nbx][nby] == '#') continue;
int w = (nax == p[3] && nay == p[4]); // 箱子移动了记1
if(!vis[nax][nay][nbx][nby]) {
vis[nax][nay][nbx][nby] = true;
pq.push({p[0]+w, nax, nay, nbx, nby});
}
}
}
return -1;
}
};
方法二:01队列+BFS
由于步数要么加1,要么不变,即只用01两种。可以用01队列代替优先队列,也就是01BFS。
class Solution {
public:
bool vis[25][25][25][25];
const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
int minPushBox(vector<vector<char>>& grid) {
memset(vis, 0, sizeof(vis));
deque<vector<int>> pq; // 01队列
int row = grid.size(), col = grid[0].size();
int ax, ay, bx, by, ex, ey;
for(int i = 0;i < row;i++) {
for(int j = 0;j < col;j++) {
if(grid[i][j] == 'S') {
ax = i, ay = j;
grid[i][j] = '.';
}
if(grid[i][j] == 'B') {
bx = i, by = j;
grid[i][j] = '.';
}
if(grid[i][j] == 'T') {
ex = i, ey = j;
}
}
}
pq.push_front({0, ax, ay, bx, by}); // 步数,人,箱子
vis[ax][ay][bx][by] = true;
while(!pq.empty()) {
auto p = pq.front();pq.pop_front();
// cout << p[0] << " " << p[1] << " " << p[2] << " " << p[3] << " " << p[4] << endl;
if(p[3] == ex && p[4] == ey) return p[0];
for(int i = 0;i < 4;i++) {
int nax = p[1]+dx[i], nay = p[2]+dy[i]; // 人
if(nax < 0 || nax >= row || nay < 0 || nay >= col || grid[nax][nay] == '#') continue;
int nbx = (nax == p[3] && nay == p[4] ? p[3]+dx[i] : p[3]); // 箱子要么随人走,要么不动
int nby = (nax == p[3] && nay == p[4] ? p[4]+dy[i] : p[4]);
if(nbx < 0 || nbx >= row || nby < 0 || nby >= col || grid[nbx][nby] == '#') continue;
int w = (nax == p[3] && nay == p[4]); // 箱子移动了记1
if(!vis[nax][nay][nbx][nby]) {
vis[nax][nay][nbx][nby] = true;
if(w == 0) pq.push_front({p[0], nax, nay, nbx, nby});
else pq.push_back({p[0]+w, nax, nay, nbx, nby});
}
}
}
return -1;
}
};