Leetcode 多维度dp+优先队列+bfs

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;
    }
};
个性签名:时间会解决一切
原文地址:https://www.cnblogs.com/lfri/p/15795789.html