Shortest Path to Get All Keys in C++


Suppose we have a grid. There are few symbols. "." is indicating empty cell, "#" is for wall, "@" is for starting point, ("a", "b", ...) all are keys, and ("A", "B", ...) all are locks. We will start from the starting point, and one move consists of walking one space in one of the 4 directions (left, right, top, bottom). We will not go outside the grid, and there are walls to block our way. If we walk over a key, we pick it up. We can't walk over a lock unless we have the corresponding key.

For each lock like A, B etc we have keys like a, b, etc, so locks are same letter in uppercase letters and keys are same with lower case letters.

We have to find the lowest number of moves to acquire all keys. If it's impossible, return -1.

So, if the input is like ["@.a.#","###.#","b.A.B"], then the output will be 8

To solve this, we will follow these steps −

  • n := number of rows, m := number of columns

  • Define an array start of size 3

  • cnt := 0

  • for initialize i := 0, when i < n, update (increase i by 1), do −

    • for initialize j := 0, when j < m, update (increase j by 1), do −

      • if grid[i, j] is same as '@', then −

        • start[1] := i, start[2] := j

      • if grid[i, j] >= 'a' and grid[i, j] <= 'f', then −

        • cnt := maximum of cnt and grid[i, j] - 'a' + 1

  • Define one set visited

  • req := 2^(cnt - 1)

  • Define one queue q of arrays

  • insert start into q

  • insert start into visited

  • level := 0

  • while (not q is empty), do −

    • sz := size of q

    • while sz is non-zero, decrease sz after each iteration, do −

      • Define an array curr := front element of q

      • delete element from q

      • key := curr[0]

      • if key is same as req, then −

        • return level

      • x := curr[1], y := curr[2]

      • prevKey := key

      • for initialize i := 0, when i < 4, update (increase i by 1), do −

        • nx := x + dir[i, 0], ny := y + dir[i, 1]

        • key := prevKey

        • if nx >= 0 and ny >= 0 and nx < n and ny < m, then −

          • if grid[nx, ny] is same as '#', then −

            • Ignore following part, skip to the next iteration

          • if grid[nx, ny] >= 'a' and grid[nx, ny] <= 'f', then −

            • key := key OR (2^(grid[nx, ny] - ASCII of 'a'))

          • if grid[nx, ny] >= 'A' and grid[nx, ny] <= 'F', then −

            • if (shift key to the right (grid[nx, ny] - ASCII of 'A') times AND 1) is same as 0, then −

              • Ignore following part, skip to the next iteration

          • Define an array state({ key, nx, ny })

          • if state is in visited, then −

            • Ignore following part, skip to the next iteration

          • insert state into q

          • insert state into visited

    • (increase level by 1)

  • return -1

Let us see the following implementation to get better understanding −

Example

 Live Demo

#include <bits/stdc++.h>
using namespace std;
int dir[4][2] = {{1, 0}, {-1, 0}, {0, -1}, {0, 1}};
class Solution {
   public:
   int shortestPathAllKeys(vector<string>& grid) {
      int n = grid.size();
      int m = grid[0].size();
      vector<int> start(3);
      int cnt = 0;
      for (int i = 0; i < n; i++) {
         for (int j = 0; j < m; j++) {
            if (grid[i][j] == '@') {
               start[1] = i;
               start[2] = j;
            }
            if (grid[i][j] >= 'a' && grid[i][j] <= 'f') {
               cnt = max(cnt, grid[i][j] - 'a' + 1);
            }
         }
      }
      set<vector<int> > visited;
      int req = (1 << cnt) - 1;
      queue<vector<int> > q;
      q.push(start);
      visited.insert(start);
      int level = 0;
      while (!q.empty()) {
         int sz = q.size();
         while (sz--) {
            vector<int> curr = q.front();
            q.pop();
            int key = curr[0];
            if (key == req)
            return level;
            int x = curr[1];
            int y = curr[2];
            int nx, ny;
            int prevKey = key;
            for (int i = 0; i < 4; i++) {
               nx = x + dir[i][0];
               ny = y + dir[i][1];
               key = prevKey;
               if (nx >= 0 && ny >= 0 && nx < n && ny < m) {
                  if (grid[nx][ny] == '#')
                  continue;
                  if (grid[nx][ny] >= 'a' && grid[nx][ny] <=
                  'f') {
                     key |= (1 << (grid[nx][ny] - 'a'));
                  }
                  if (grid[nx][ny] >= 'A' && grid[nx][ny] <=
                  'F') {
                     if (((key >> (grid[nx][ny] - 'A')) & 1)
                     == 0)
                     continue;
                  }
                  vector<int> state({ key, nx, ny });
                  if (visited.count(state))
                  continue;
                  q.push(state);
                  visited.insert(state);
               }
            }
         }
         level++;
      }
      return -1;
   }
};
main(){
   Solution ob;
   vector<string> v = {"@.a.#","###.#","b.A.B"};
   cout << (ob.shortestPathAllKeys(v));
}

Input

{"@.a.#","###.#","b.A.B"}

Output

8

Updated on: 08-Jun-2020

434 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements