当前位置: 首页 > article >正文

[leetcode]864. 获取所有钥匙的最短路径(状态压缩bitmask+bfs)

题目链接

题意

给定一个 n × m n\times m n×m的地图
‘.’ 代表一个空房间
‘#’ 代表一堵墙
‘@’ 是起点
小写字母代表钥匙
大写字母代表锁
钥匙和门互为大小写

目的是收集所有钥匙 不一定要把门都打开
求最少需要几步
数据范围: n , m ≤ 30 , k 对钥匙和门 , k ≤ 6 n,m\leq 30,k对钥匙和门,k\leq 6 n,m30,k对钥匙和门,k6

思路

  • 数据很小 显然搜索 但是我一开始写的dfs错了 求最少步数还是bfs更合适

  • 本题的重点是vis有第三个状态 就是当前手中的钥匙情况
    而不是简单的标记走过的点不能再走 因为可能需要走到一个角落拿钥匙 还需要原路返回 所以点可以重复走
    但是 如果拥有钥匙情况不变 就不能重复走某个点 因为这样是无意义的 浪费步数

  • 一定要想清楚这一维再开始写代码

Code

#define pii pair<int,int>
#define ar2 array<int,2>
#define ar3 array<int,3>
#define ar4 array<int,4>
#define endl '\n'
void cmax(int &a,int b){a=max(a,b);};
void cmin(int &a,int b){a=min(a,b);};
const int N=40,MOD=1e9+7,INF=0x3f3f3f3f;const long long LINF=LLONG_MAX;const double eps=1e-6;
char g[N][N];
int n,m;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
bool vis[N][N][1<<7];

class Solution {
public:
    int k=0;
    int sx,sy;
    int shortestPathAllKeys(vector<string>& grid) {
        n=grid.size(),m=grid[0].size();
        memset(vis,0,sizeof vis);

        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                g[i+1][j+1]=grid[i][j];
            }
        }

        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(g[i][j]=='@') sx=i,sy=j;
                if(isupper(g[i][j])) k++;
            }
        }

        int ans=bfs();
        return ans;
    }

    int bfs(){
        queue<ar4>q;
        q.push({sx,sy,0,0});//steps keys
        vis[sx][sy][0]=1;

        int finalst=(1<<k)-1;
        

        while(q.size()){
            auto [x,y,steps,key]=q.front();q.pop();
            if(key==finalst){
                return steps;
            }

            for(int i=0;i<4;i++){
                int tx=x+dx[i],ty=y+dy[i];
                if(tx<1||tx>n||ty<1||ty>m||g[tx][ty]=='#') continue;
                if(vis[tx][ty][key]) continue;
                
                char c=g[tx][ty];
                int newkey=key;
                
                if(islower(c)){
                    newkey|=(1<<(c-'a'));
                }

                if(isupper(c)){
                    if((key&(1<<(c-'A')))==0) continue;
                }

                vis[tx][ty][newkey]=1;
                q.push({tx,ty,steps+1,newkey});
            }
        }
        return -1;
    }
};

实现细节

如何使用bitmask状态压缩 来表示当前钥匙状态?

在二进制意义上看 最多6个钥匙 也就是最多 ( 1 < < 6 ) 10 = 2 6 = 64 (1<<6)_{10}=2^6=64 (1<<6)10=26=64
v i s 中 30 ∗ 30 ∗ 64 空间完全开得下 vis中30*30*64空间完全开得下 vis303064空间完全开得下

说回bitmask 二进制上每一位代表这一位所对应的钥匙是否获得 通过c-'a’进行映射

队列存储四维内容

保存这个状态的坐标 走的步数 当前钥匙状态


http://www.kler.cn/a/596136.html

相关文章:

  • 从两层 C/S 到 B/S 架构演进分析:技术驱动与业务需求的辩证关系
  • 归并排序的思路与实现
  • 卷积神经网络Batch Normalization的作用
  • 体育直播视频源格式解析:M3U8 vs FLV
  • LeetCode215. 数组中的第K个最大元素
  • Redis Lua脚本实现令牌桶限流算法
  • 常用的 MyBatis 标签及其作用
  • 第5节:AWK环境准备
  • dedecms织梦【php网站】-----获取webshell攻略
  • Trae初使用心得(Java后端)
  • Qt搭配CLion:Mac电脑M芯片Qt开发环境
  • OpenCV专利收费免费模块介绍
  • 虚拟机 | Ubuntu操作系统:su和sudo理解及如何处理忘记root密码
  • AsyncHttpClient使用说明书
  • 【Python机器学习】3.2. 决策树理论(进阶):ID3算法、信息熵原理、信息增益
  • QT国产化系统软件开发
  • DeepSeek写打台球手机小游戏
  • 安装CentOS7
  • 211 本硕研三,已拿 C++ 桌面应用研发 offer,计划转音视频或嵌入式如何规划学习路线?
  • 股票量化交易开发 Yfinance