1. 程式人生 > 實用技巧 >LeetCode 每日一題 LCP 13. 尋寶

LeetCode 每日一題 LCP 13. 尋寶

題目連結:LCP 13.尋寶

題面

我們得到了一副藏寶圖,藏寶圖顯示,在一個迷宮中存在著未被世人發現的寶藏。

迷宮是一個二維矩陣,用一個字串陣列表示。它標識了唯一的入口(用 'S' 表示),和唯一的寶藏地點(用 'T'
表示)。但是,寶藏被一些隱蔽的機關保護了起來。在地圖上有若干個機關點(用 'M' 表示), 只有所有機關均被觸發,才可以拿到寶藏。

要保持機關的觸發,需要把一個重石放在上面。迷宮中有若干個石堆(用 'O' 表示),每個石堆都有 無限
個足夠觸發機關的重石。但是由於石頭太重,我們一次只能搬 一個 石頭到指定地點。

迷宮中同樣有一些牆壁(用 '#' 表示),我們不能走入牆壁。剩餘的都是可隨意通行的點(用 '.'
表示)。石堆、機關、起點和終點(無論是否能拿到寶藏)也是可以通行的。

我們每步可以選擇向上/向下/向左/向右移動一格,並且不能移出迷宮。搬起石頭和放下石頭不算步數。那麼,從起點開始,我們最少需要多少步才能最後拿到寶藏呢?如果無法拿到寶藏,返回
-1 。

示例 Sample

示例 1:

輸入: ["S#O", "M..", "M.T"]

輸出:16

解釋:最優路線為: S->O, cost = 4, 去搬石頭 O->第二行的M, cost = 3, M機關觸發 第二行的M->O, cost = 3,
我們需要繼續回去 O 搬石頭。 O->第三行的M, cost = 4, 此時所有機關均觸發 第三行的M->T, cost = 2,去T點拿寶藏。
總步數為16。

示例 2:

輸入: ["S#O", "M.#", "M.T"]

輸出:-1

解釋:我們無法搬到石頭觸發機關

示例 3:

輸入: ["S#O", "M.T", "M.."]

輸出:17

解釋:注意終點也是可以通行的。

限制:

  • 1 <= maze.length <= 100
  • 1 <= maze[i].length <= 100
  • maze[i].length == maze[j].length
  • S 和 T 有且只有一個
  • 0 <= M的數量 <= 16
  • 0 <= O的數量 <= 40,題目保證當迷宮中存在 M 時,一定存在至少一個 O 。

我的題解

這題比較容易超時,需要預處理出所有點(S T O M ,但不含 . #)間的距離。
這裡我用 dist[i][j] 表示 i 到 j 的距離(i、j為 S T M),包含需要搬石頭的移動距離(T 不需要,其餘都要)。
剩下的簡單 DP 即可。

typedef pair<int, int> P;

class Solution {
 public:
  int gao(const vector<string>& maze, P s, P t, map<pair<P, P>, int>&mem) {
    const int n = maze.size();
    const int m = maze[0].length();
    const int dx[] = {1, -1, 0, 0};
    const int dy[] = {0, 0, 1, -1};

    if(mem.find({s, t}) != mem.end())
      return mem[ {s, t}];

    vector<vector<bool>>vis(n, vector<bool>(m, false));
    vector<vector<int>>dis(n, vector<int>(m, INT_MAX));
    queue<P>que;
    que.push(s);
    vis[s.first][s.second] = true, dis[s.first][s.second] = 0;
    while(!que.empty()) {
      P u = que.front();
      que.pop();
      if(u == t) {
        mem[ {s, t}] = mem[ {t, s}] = dis[u.first][u.second];
      }
      for(int i = 0; i < 4; ++i) {
        P v(u.first + dx[i], u.second + dy[i]);
        if(v.first >= 0 && v.first < n && v.second >= 0 && v.second < m && maze[v.first][v.second] != '#') {
          dis[v.first][v.second] = min(dis[v.first][v.second], dis[u.first][u.second] + 1);
          if(maze[v.first][v.second] != '.')
            mem[ {s, v}] = mem[ {v, s}] = dis[v.first][v.second];
          if(!vis[v.first][v.second]) {
            vis[v.first][v.second] = true;
            que.push(v);
          }
        }
      }
    }
    if(mem.find({s, t}) != mem.end())
      return mem[ {s, t}];
    else
      return -1;
  }

  int minimalSteps(vector<string>& maze) {
    const int n = maze.size();
    const int m = maze[0].length();
    P s, t;
    vector<P>g(2);
    vector<P>h;
    map<pair<P, P>, int>mem;
    for(int i = 0; i < n; i++) {
      for(int j = 0; j < m; j++)
        if(maze[i][j] == 'S')
          g[0] = {i, j};
        else if(maze[i][j] == 'T')
          g[1] = {i, j};
        else if(maze[i][j] == 'M')
          g.push_back({i, j});
        else if(maze[i][j] == 'O')
          h.push_back({i, j});
    }
    vector<vector<int>> dis(g.size(), vector<int>(1 << g.size(), INT_MAX));
    vector<vector<int>>dist(g.size(), vector<int>(g.size(), INT_MAX));
    for(int i = 0; i < (int)g.size(); i++)
      for(int j = 0; j < i; j++) {
        if(i == 1 || j == 1) {
          dist[i][j] = gao(maze, g[i], g[j], mem);
          dist[i][j] = dist[j][i] = dist[i][j] == -1 ? INT_MAX : dist[i][j];
        } else
          for(P k : h) {
            int d1 = gao(maze, g[i], k, mem);
            if(d1 == -1)
              continue;
            int d2 = gao(maze, k, g[j], mem);
            if(d1 != -1 && d2 != -1 && dist[i][j] > d1 + d2)
              dist[i][j] = dist[j][i] = d1 + d2;
          }
      }
    dis[0][1] = 0;/// [addr][status]
    for(int i = 1; i < (1 << g.size()); i++) { /// status
      for(int j = 0; j < (int)g.size(); j++) {
        if(!(i & (1 << j)))
          continue;
        for(int k = 0; k < (int)g.size(); k++) {
          if(!(i & (1 << k)) || k == j)
            continue;
          if(dist[k][j] == INT_MAX || dis[k][i ^ (1 << j)] == INT_MAX)
            continue;
          dis[j][i] = min(dis[j][i], dis[k][i ^ (1 << j)] + dist[k][j]);
        }
      }
    }
    return dis[1][(1 << g.size()) - 1] == INT_MAX ? -1 : dis[1][(1 << g.size()) - 1];
  }
};