zoukankan      html  css  js  c++  java
  • 1263. Minimum Moves to Move a Box to Their Target Location

    问题:

    推箱子问题。

    给定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 };
  • 相关阅读:
    Volatile关键字的解读
    JVM内存模型
    Redis为何是单线程的
    乐观锁&CAS问题
    String为什么要设置成Final类型
    后端开发之光!Django应用的容器化部署实践~
    一小时完成后台开发:DjangoRestFramework开发实践
    Django快速开发实践:Drf框架和xadmin配置指北
    Django应用部署:nginx+uwsgi方式
    Python踩坑:类与类对象类型参数传递与使用
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/14538733.html
Copyright © 2011-2022 走看看