给定一个二维网格 grid。 "." 代表一个空房间, "#" 代表一堵墙, "@" 是起点,("a", "b", ...)代表钥匙,("A", "B", ...)代表锁。
我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间。我们不能在网格外面行走,也无法穿过一堵墙。如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。
假设 K 为钥匙/锁的个数,且满足 1 <= K <= 6,字母表中的前 K 个字母在网格中都有自己对应的一个小写和一个大写字母。换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁。另外,代表钥匙和锁的字母互为大小写并按字母顺序排列。
返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shortest-path-to-get-all-keys
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
public:
struct State {
int x, y, key;
State(int x, int y, int key):x(x), y(y), key(key){}
State():x(0), y(0), key(0){}
};
bool vis[31][31][1 << 6];
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
int ans = 0;
int st_x, st_y;
int cnt = 0;
int shortestPathAllKeys(vector<string>& grid) {
int n = grid.size();
int m = grid[0].size();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == '@') {
st_x = i;
st_y = j;
}
if (islower(grid[i][j])) {
cnt++;
}
}
}
int mask = (1 << cnt) - 1;
queue <State> q;
q.push(State(st_x, st_y, 0));
vis[st_x][st_y][0] = true;
while (!q.empty()) {
// 用len记录当前队列长度,不要直接使用q.size()
int len = q.size();
for (int k = 0; k < len; k++) {
auto cur = q.front();q.pop();
// 如果所有锁都已经解开,则返回答案
if ((cur.key & mask) == mask) {
return ans;
}
for (int i = 0; i < 4; i++) {
int tx = cur.x + dir[i][0];
int ty = cur.y + dir[i][1];
if (tx < 0 || tx >= n || ty < 0 || ty >= m) {
continue;
}
char ch = grid[tx][ty];
// 如果遇到墙
if (ch == '#') {
continue;
}
// 如果是锁
if (isupper(ch)) {
// 如果当前没有解对应所的钥匙,则没法走,返回
if ( ((cur.key >> (ch - 'A') & 1) != 1) {
continue;
}
}
// 保存当前状态
int temp = cur.key;
// 如果是钥匙,则更新状态
if (islower(ch)) {
temp |= (1 << (ch - 'a'));
}
if (vis[tx][ty][temp]) {
continue;
}
vis[tx][ty][temp] = true;
q.push(State(tx, ty, temp));
}
}
ans++;
}
return -1;
}
};