Skip to content

Commit fbfbc22

Browse files
authored
Create shortest-path-to-get-all-keys.cpp
1 parent 6e34235 commit fbfbc22

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

C++/shortest-path-to-get-all-keys.cpp

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Time: O(k*r*c + |E|log|V|) = O(k*r*c + (k*|V|)*log|V|)
2+
// = O(k*r*c + (k*(k*2^k))*log(k*2^k))
3+
// = O(k*r*c + (k*(k*2^k))*(logk + k*log2))
4+
// = O(k*r*c + (k*(k*2^k))*k)
5+
// = O(k*r*c + k^3*2^k)
6+
// Space: O(|V|) = O(k*2^k)
7+
8+
class Solution {
9+
public:
10+
int shortestPathAllKeys(vector<string>& grid) {
11+
unordered_map<char, pair<int, int>> locations;
12+
for (int r = 0; r < grid.size(); ++r) {
13+
for (int c = 0; c < grid[0].size(); ++c) {
14+
if (string(".#").find(grid[r][c]) == string::npos) {
15+
locations[grid[r][c]] = make_pair(r, c);
16+
}
17+
}
18+
}
19+
unordered_map<char, unordered_map<char, int>> dists;
20+
for (const auto& kvp : locations) {
21+
dists[kvp.first] = bfs(grid, kvp.first, locations);
22+
}
23+
24+
// Dijkstra's algorithm
25+
using T = tuple<int, char, int>;
26+
priority_queue<T, vector<T>, greater<T>> min_heap;
27+
min_heap.emplace(0, '@', 0);
28+
unordered_map<char, unordered_map<int, int>> best;
29+
best['@'][0] = 0;
30+
int count = 0;
31+
for (const auto& kvp : locations) {
32+
if (islower(kvp.first)) {
33+
++count;
34+
}
35+
}
36+
uint32_t target_state = (1 << count) - 1;
37+
while (!min_heap.empty()) {
38+
int cur_d, state;
39+
char place;
40+
tie(cur_d, place, state) = min_heap.top(); min_heap.pop();
41+
if (best.count(place) &&
42+
best[place].count(state) &&
43+
best[place][state] < cur_d) {
44+
continue;
45+
}
46+
if (state == target_state) {
47+
return cur_d;
48+
}
49+
for (const auto& kvp : dists[place]) {
50+
int dest, d;
51+
tie(dest, d) = kvp;
52+
auto next_state = state;
53+
if (islower(dest)) {
54+
next_state |= (1 << (dest - 'a'));
55+
} else if (isupper(dest)) {
56+
if (!(state & (1 << (dest - 'A')))) {
57+
continue;
58+
}
59+
}
60+
if (!best.count(dest) ||
61+
!best[dest].count(next_state) ||
62+
cur_d + d < best[dest][next_state]) {
63+
best[dest][next_state] = cur_d + d;
64+
min_heap.emplace(cur_d + d, dest, next_state);
65+
}
66+
}
67+
}
68+
return -1;
69+
}
70+
71+
private:
72+
unordered_map<char, int> bfs(const vector<string>&grid,
73+
char source,
74+
const unordered_map<char, pair<int, int>>& locations) {
75+
static const vector<pair<int, int>> directions{{0, -1}, {0, 1},
76+
{-1, 0}, {1, 0}};
77+
int r, c;
78+
tie(r, c) = locations.at(source);
79+
vector<vector<bool>> lookup(grid.size(), vector<bool>(grid[0].size()));
80+
lookup[r][c] = true;
81+
queue<tuple<int, int, int>> q;
82+
q.emplace(r, c, 0);
83+
unordered_map<char, int> dist;
84+
while (!q.empty()) {
85+
int r, c, d;
86+
tie(r, c, d) = q.front(); q.pop();
87+
if (source != grid[r][c] && grid[r][c] != '.') {
88+
dist[grid[r][c]] = d;
89+
continue;
90+
}
91+
for (const auto& dir : directions) {
92+
int cr = r + dir.first, cc = c + dir.second;
93+
if (!((0 <= cr && cr < grid.size()) &&
94+
(0 <= cc && cc < grid[0].size()))) {
95+
continue;
96+
}
97+
if (grid[cr][cc] != '#' && !lookup[cr][cc]) {
98+
lookup[cr][cc] = true;
99+
q.emplace(cr, cc, d + 1);
100+
}
101+
}
102+
}
103+
return dist ;
104+
}
105+
};

0 commit comments

Comments
 (0)