LeetCode 1263. 推箱子(BFS+DFS / 自定义哈希set)

文章目录

    • 1. 题目
    • 2. 解题
      • 2.1 超时解
      • 2.2 BFS + DFS

1. 题目

「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓库中的目标位置。

游戏地图用大小为 n * m 的网格 grid 表示,其中每个元素可以是墙、地板或者是箱子。

现在你将作为玩家参与游戏,按规则将箱子 'B' 移动到目标位置 'T'

  • 玩家用字符 'S' 表示,只要他在地板上,就可以在网格中向上、下、左、右四个方向移动。
  • 地板用字符 '.' 表示,意味着可以自由行走。
  • 墙用字符 '#' 表示,意味着障碍物,不能通行。
  • 箱子仅有一个,用字符 'B' 表示。相应地,网格上有一个目标位置 'T'

玩家需要站在箱子旁边,然后沿着箱子的方向进行移动,此时箱子会被移动到相邻的地板单元格。记作一次「推动」。
玩家无法越过箱子。
返回将箱子推到目标位置的最小 推动 次数,如果无法做到,请返回 -1。

示例 1:

输入:grid = [["#","#","#","#","#","#"],["#","T","#","#","#","#"],["#",".",".","B",".","#"],["#",".","#","#",".","#"],["#",".",".",".","S","#"],["#","#","#","#","#","#"]]
输出:3
解释:我们只需要返回推箱子的次数。示例 2:
输入:grid = [["#","#","#","#","#","#"],["#","T","#","#","#","#"],["#",".",".","B",".","#"],["#","#","#","#",".","#"],["#",".",".",".","S","#"],["#","#","#","#","#","#"]]
输出:-1示例 3:
输入:grid = [["#","#","#","#","#","#"],["#","T",".",".","#","#"],["#",".","#","B",".","#"],["#",".",".",".",".","#"],["#",".",".",".","S","#"],["#","#","#","#","#","#"]]
输出:5
解释:向下、向左、向左、向上再向上。示例 4:
输入:grid = [["#","#","#","#","#","#","#"],["#","S","#",".","B","T","#"],["#","#","#","#","#","#","#"]]
输出:-1提示:
1 <= grid.length <= 20
1 <= grid[i].length <= 20
grid 仅包含字符 '.', '#',  'S' , 'T', 以及 'B'。
grid 中 'S', 'B''T' 各只能出现一个。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-moves-to-move-a-box-to-their-target-location
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 解题

2.1 超时解

15 / 18 个通过测试用例

  • 优先队列里存入 box 和 人的4个坐标位置,以及推的次数,推的次数小的优先
  • 队列里存了太多的状态
class node
{
public:int push, bi, bj, pi, pj;node(int n, int a, int b, int c, int d){push = n;bi = a;bj = b;pi = c;pj = d;}
};
struct hashf // 自定义哈希
{unsigned long long operator()(node v) const{return 1ULL*v.push*pow(21,4)+v.bi*pow(21,3)+v.bj*pow(21,2)+v.pi*21+v.pj;}
};
struct eqf // 哈希set 相等判断函数
{bool operator()(node v1, node v2) const//不能写引用,会报错{return v1.push==v2.push && v1.bi==v2.bi && v1.bj==v2.bj&& v1.pi==v2.pi && v1.pj==v2.pj;}
};
struct cmp
{bool operator()(node& a, node& b) const{return a.push > b.push;//推得次数少的优先}
};
class Solution {
public:int minPushBox(vector<vector<char>>& grid) {int m = grid.size(), n = grid[0].size(), k = 21;int targetx, targety, boxi, boxj, peoplei, peoplej, push = 0, size;for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){if(grid[i][j] == 'S')peoplei = i, peoplej = j;else if(grid[i][j] == 'B')boxi = i, boxj = j;else if(grid[i][j] == 'T')targetx = i, targety = j;}}vector<vector<int>> dir = {{1,0},{0,1},{0,-1},{-1,0}};priority_queue<node, vector<node>, cmp> q; node state(0, boxi, boxj, peoplei, peoplej);q.push(state);unordered_set<node, hashf, eqf> vis;vis.insert(state);while(!q.empty()){int pj = q.top().pj;int pi = q.top().pi;int bj = q.top().bj;int bi = q.top().bi;push = q.top().push;if(bi==targetx && bj==targety)return push;q.pop();int nextbi, nextbj, nextpi, nextpj;for(int d = 0; d < 4; d++){nextpi = pi+dir[d][0];nextpj = pj+dir[d][1];state.push = push;if(nextpi==bi && nextpj==bj){	// 推动箱子了nextbi = bi+dir[d][0];nextbj = bj+dir[d][1];state.push++;}else{nextbi = bi;nextbj = bj;}state.bi = nextbi;state.bj = nextbj;state.pi = nextpi;state.pj = nextpj;if(nextpi>=0 && nextpi<m && nextpj>=0 && nextpj<n &&nextbi>=0 && nextbi<m && nextbj>=0 && nextbj<n &&grid[nextpi][nextpj] != '#' && grid[nextbi][nextbj] != '#' &&vis.find(state) == vis.end()){vis.insert(state);q.push(state);}}}return -1;}
};

2.2 BFS + DFS

  • 队列里面只存能推动箱子的状态
  • 中间到达推箱子的过程,不必记录到队列内,采用DFS判断人的位置能否到达推动箱子的位置
  • 不采用优先队列也可以
class node
{
public:int push, bi, bj, pi, pj;node(int n, int a, int b, int c, int d){push = n;bi = a;bj = b;pi = c;pj = d;}
};
struct hashf
{unsigned long long operator()(node v) const{return 1ULL*v.bi*pow(21,3)+v.bj*pow(21,2)+v.pi*21+v.pj;}
};
struct eqf
{bool operator()(node v1, node v2) const//不能写引用{return v1.bi==v2.bi && v1.bj==v2.bj&& v1.pi==v2.pi && v1.pj==v2.pj;//2个物品的位置都相等即set中出现过了}
};
struct cmp
{bool operator()(node& a, node& b) const{return a.push > b.push;//推得次数少的优先}
};
class Solution {vector<vector<int>> dir = {{1,0},{0,1},{0,-1},{-1,0}};
public:int minPushBox(vector<vector<char>>& grid) {int m = grid.size(), n = grid[0].size();int targetx, targety, boxi, boxj, peoplei, peoplej, push = 0, size;for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){if(grid[i][j] == 'S')peoplei = i, peoplej = j;else if(grid[i][j] == 'B')boxi = i, boxj = j;else if(grid[i][j] == 'T')targetx = i, targety = j;}}priority_queue<node, vector<node>, cmp> q; node state(0, boxi, boxj, peoplei, peoplej);q.push(state);unordered_set<node, hashf, eqf> vis;vis.insert(state);while(!q.empty()){int pj = q.top().pj;int pi = q.top().pi;int bj = q.top().bj;int bi = q.top().bi;push = q.top().push;if(bi==targetx && bj==targety)return push;q.pop();int nextbi, nextbj, nextpi, nextpj, pushPosx, pushPosy;for(int d = 0; d < 4; d++){nextbi = bi+dir[d][0];nextbj = bj+dir[d][1];if(nextbi<0 || nextbi>=m || nextbj<0 || nextbj>=n || grid[nextbi][nextbj] == '#')continue; // 箱子下一个位置不合法nextpi = bi;nextpj = bj;pushPosx = bi-dir[d][0];//人推动箱子前的位置pushPosy = bj-dir[d][1];if(pushPosx<0 || pushPosx>=m || pushPosy<0 || pushPosy>=n || grid[pushPosx][pushPosy] == '#')continue; // 推箱子位置不合法vector<vector<bool>> record(m, vector<bool>(n, false));if(!canReachPushPos(grid,pi,pj,bi,bj,pushPosx,pushPosy,record))continue;//不能从当前位置到达推箱子位置state.push = push+1;state.bi = nextbi;state.bj = nextbj;state.pi = nextpi;state.pj = nextpj;if(vis.find(state) == vis.end()){vis.insert(state);q.push(state);}}}return -1;}bool canReachPushPos(vector<vector<char>>& grid, int x0, int y0, int bi, int bj, int tx, int ty, vector<vector<bool>>& vis){vis[x0][y0] = true;if(x0==tx && y0==ty) return true;int m = grid.size(), n = grid[0].size();for(int k = 0; k < 4; k++){int nx = x0+dir[k][0];int ny = y0+dir[k][1];if(nx>=0 && nx<m && ny>=0 && ny<n && grid[nx][ny] != '#' && !(nx==bi && ny==bj) && !vis[nx][ny]){   // box 也不能穿过if(canReachPushPos(grid,nx, ny,bi,bj,tx,ty, vis))return true;}}return false;}
};

240 ms 20.4 MB C++


我的CSDN博客地址 https://michael.blog.csdn.net/

长按或扫码关注我的公众号(Michael阿明),一起加油、一起学习进步!
Michael阿明

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/473258.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入浅出Java回调机制

前几天看了一下Spring的部分源码&#xff0c;发现回调机制被大量使用&#xff0c;觉得有必要把Java回调机制的理解归纳总结一下&#xff0c;以方便在研究类似于Spring源码这样的代码时能更加得心应手。 注&#xff1a;本文不想扯很多拗口的话来充场面&#xff0c;我的目的是希望…

前端:实现div等块元素添加X轴滚动显示(Y轴不滚动)

一、建立外盒子与内盒子 原生态代码&#xff1a; <div class"tol_dev"><div class"dev_li"></div><div class"dev_li"></div><div class"dev_li"></div><div class"dev_li"…

2020年学习总结

文章目录1. CSDN 博客数据2. 基础算法练习3. 机器学习4. 深度学习5. MySQL6. 总结和展望时间过得很快&#xff0c;2020结束了&#xff01; 写个流水账&#xff0c;记录一下。 1. CSDN 博客数据 截个图对比下&#xff1a; 2019年终2020年终 2. 基础算法练习 LeetCode 刷题 …

npm全局环境变量配置及解决VsCode使用时遇到的问题

一、npm全局环境变量配置 1、我们要先配置npm的全局模块的存放路径以及cache的路径 例如我希望将以上两个文件夹放在NodeJS的主目录下&#xff0c;便在NodeJs下建立”node_global”及”node_cache”两个文件夹。如下图 2、cmd 中输入如下命令 npm config set prefix “d:\no…

Android菜鸟如何学习Android系统开发?

如何做好Android学习前的准备? 如果你已经确定了学习Android的目标&#xff0c;那么&#xff0c;应该提前做好哪些工作、先打下哪些基础呢? 首先&#xff0c;你最好先熟悉一门编程语言&#xff0c;现在大学里面和计算机相关的专业甚至理工类专业一般都会开设C语言课程&#x…

关于Django中JsonResponse返回中文字典编码错误的解决方案

遇到这样一个问题&#xff0c;返回的json不是中文 def get_json(request):return JsonResponse({"res": "成功"}) 结果&#xff1a; {"res": "\u6210\u529f"} 解决方案&#xff1a;JsonResponse(data, json_dumps_params{ensure_a…

LeetCode 668. 乘法表中第k小的数(二分查找)

文章目录1. 题目2. 解题1. 题目 几乎每一个人都用 乘法表。但是你能在乘法表中快速找到第k小的数字吗&#xff1f; 给定高度m 、宽度n 的一张 m * n的乘法表&#xff0c;以及正整数k&#xff0c;你需要返回表中第k 小的数字。 例 1&#xff1a; 输入: m 3, n 3, k 5 输出…

天池 在线编程 寻找比周围都大的点(模拟)

文章目录1. 题目2. 解题1. 题目 https://tianchi.aliyun.com/oj/245679029019779851/254275128279634587 给一个n*m大小的矩阵&#xff0c;寻找矩阵中所有比邻居&#xff08;上下左右&#xff0c;对角也算&#xff0c;不考虑边界就是8个咯&#xff09;都严格大的点。 返回一个…

[原创][R语言]股票分析实战[4]:周级别涨幅趋势的相关性

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、D…

前端:实现手机左右滑动效果

需求&#xff1a;手机可以左右滑动&#xff0c;显示商品或者div信息 原理&#xff1a;建立两个盒子&#xff0c;一个是可以看到的手机屏幕盒子&#xff0c;一个是自己设定好的盒子&#xff0c;左右滑动&#xff0c;只显示与手机屏幕盒子交集的部分 代码&#xff1a; <div …

天池 在线编程 双向取数(博弈DP)

文章目录1. 题目2. 解题1. 题目 https://tianchi.aliyun.com/oj/245679029019779851/254275128279634585 有一个长度为n的数列arr&#xff0c; 甲乙两个人每次可以从头或者从末尾取一个数&#xff0c;双方都想让自己取数之和尽量多&#xff0c; 甲先取数&#xff0c;问甲乙在…

前端demo:实现背景半透明,div与文本正常显示

一、需求&#xff1a; 背景实现透明度0.3&#xff0c;其他组件正常显示 二、代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-widt…

天池 在线编程 布尔表达式求值(栈)

文章目录1. 题目2. 解题1. 题目 https://tianchi.aliyun.com/oj/245679029019779851/254275128279634588 给定一个字符串代表一个仅包含"true","false","or","and"的布尔表达式。 你的任务是将这个表达式的值求出&#xff0c;返回&q…

Schema详解

XML Schema 简介XSD 为何使用XML Schema 是基于 XML 的 DTD 替代者。XML Schema 可描述 XML 文档的结构。XML Schema 语言也可作为 XSD&#xff08;XML Schema Definition&#xff09;来引用。在继续学习之前&#xff0c;您需要对下面的知识有基本的了解&#xff1a;HTML / XHT…

整理总结一下:git恢复本地误删除的分支

一、使用git log -g查看日志&#xff0c;找回之前提交的commit,并记下commit_id git log -g 二、新建分支newbranch&#xff0c;把commit_id分支复制到新的分支上 git branch newbranch commit_id 三、切换新建分支newbranch&#xff0c;检查文件 git checkout newbran…

LeetCode 1074. 元素和为目标值的子矩阵数量(2d前缀和+哈希)

文章目录1. 题目2. 解题1. 题目 给出矩阵 matrix 和目标值 target&#xff0c;返回元素总和等于目标值的非空子矩阵的数量。 子矩阵 x1, y1, x2, y2 是满足 x1 < x < x2 且 y1 < y < y2 的所有单元 matrix[x][y] 的集合。 如果 (x1, y1, x2, y2) 和 (x1, y1, x2…

最炫国漫《雾山五行》用 Python 了解一下到底有多优秀

看动漫的小伙伴应该知道最近出了一部神漫《雾山五行》&#xff1a; 1、极具特色的水墨画风和超燃的打斗场面广受好评 2、首集播出不到 24 小时登顶 B 站热搜第一&#xff0c;豆瓣开分 9.5&#xff0c; 火爆程度可见一斑&#xff0c;就打斗场面而言&#xff0c;说是最炫动漫也…

LeetCode 982. 按位与为零的三元组(位运算+计数)

文章目录1. 题目2. 解题1. 题目 给定一个整数数组 A&#xff0c;找出索引为 (i, j, k) 的三元组&#xff0c;使得&#xff1a; 0 < i < A.length 0 < j < A.length 0 < k < A.length A[i] & A[j] & A[k] 0&#xff0c;其中 & 表示按位与&…

雷军一往无前的十年(小米十周年公开演讲)附赠《一往无前》电子书籍

▲雷军 | 中国企业家俱乐部理事、小米科技董事长 做全球最好的手机&#xff0c;只卖一半的价钱&#xff0c;让每个人都能买得起——如何能够实现这个看上去、听上去都不靠谱的目标&#xff1f; 来源 | 雷军公众号分享 | 雷军 2020年8月11日19:30&#xff0c;小米十周年&#x…

LeetCode 1147. 段式回文(贪心)

文章目录1. 题目2. 解题1. 题目 段式回文 其实与 一般回文 类似&#xff0c;只不过是最小的单位是 一段字符 而不是 单个字母。 举个例子&#xff0c;对于一般回文 "abcba" 是回文&#xff0c;而 "volvo" 不是&#xff0c;但如果我们把 "volvo"…