864. 获取所有钥匙的最短路径

参看bfs的一般格式
695. 岛屿的最大面积
bfs:在最短路径上,我们最多只会经过每个房间一次。因此从起点开始,使用队列进行广度优先搜索,当第一个搜索到某个节点的时候,我们就可以得到从起点到该节点正确的最短路。
本题目的关键在于:在最短路径上也不可能存在如下的情况:我们经过了某个房间两次,并且这两次我们拥有钥匙的情况是完全一致的。
所以我们使用dist[x][y][mask]来存储每个位置的状态,xy表示位置,mask是使用位运算存储钥匙状态,dist==-1时这一格子从未走过,否则存储的是到目前走过的格子数量。

class Solution {
public:
    int shortestPathAllKeys(vector<string>& grid) {
        map<char,int> keytoindex;
        int sx=0,sy=0,nx,ny;
        int row=grid.size(),col=grid[0].size();
        int tempi;
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                if(grid[i][j]=='@'){
                    sx=i;sy=j;
                }
                else if(islower(grid[i][j])){
                    if(!keytoindex.count(grid[i][j])){
                        tempi=keytoindex.size();
                        keytoindex[grid[i][j]]=tempi;
                    }
                }
            }
        }
        // for(auto [k,v]:keytoindex){
        //     cout<<k<<" "<<v<<endl;
        // }cout<<endl;
        
        int cx=sx,cy=sy;
        vector<vector<vector<int>>> dist(row,vector<vector<int>>(col,vector<int>(1<<keytoindex.size(),-1)));
        const int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
        queue<tuple<int,int,int>> bq;
        bq.emplace(cx,cy,0);
        dist[sx][sy][0]=0;

        while(!bq.empty()){
            auto [cx,cy,mask]=bq.front();
            bq.pop();
            for(int i=0;i<4;i++){
                nx=cx+dir[i][0];
                ny=cy+dir[i][1];
                if(((0<=nx&&nx<row) && (0<=ny&&ny<col)) && grid[nx][ny]!='#'){
                    if(grid[nx][ny]=='@' || grid[nx][ny]=='.'){
                        if(dist[nx][ny][mask]==-1){
                            dist[nx][ny][mask]=dist[cx][cy][mask]+1;
                             bq.emplace(nx,ny,mask);
                        }                       
                    }
                    else if(islower(grid[nx][ny])){
                        int newmask=mask | (1<<keytoindex[grid[nx][ny]]);
                        if(dist[nx][ny][newmask]==-1){
                            dist[nx][ny][newmask]=dist[cx][cy][mask]+1;
                            if(newmask==((1<<keytoindex.size())-1)){
                            return dist[nx][ny][newmask];
                            }
                            bq.emplace(nx,ny,newmask);
                        }                                                
                    }
                    else{
                        if(mask & 1<<keytoindex[tolower(grid[nx][ny])] && dist[nx][ny][mask]==-1 ){
                            dist[nx][ny][mask]=dist[cx][cy][mask]+1;
                            bq.emplace(nx,ny,mask);
                        }                        
                    }
                }
            }

            
        }
        return -1;
    }
};

注意杂项:
1. << >>左移右移运算的优先级低于加减±
2. 注意观察此处dist初始化的时候的预留空间如何书写。
数据类型(个数,子数据数据类型)
数据类型(个数,子数据的值)

vector<vector<vector<int>>> dist(
	row,vector<vector<int>>(
		col,vector<int>(
			1<<keytoindex.size(),-1
		)
	)
);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值