zoukankan      html  css  js  c++  java
  • 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。 图片.gif

    示例 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];
      }
    };
    
  • 相关阅读:
    ORACLE CASE WHEN 及 SELECT CASE WHEN的用法
    Oracle中NVARCHAR2字符集不匹配问题
    数据库读写分离
    oracle存储过程获取异常信息码和异常信息
    js删除字符串的最后一个字符三种方法
    我弄的一些TASKER配置
    分享我用Taker做任务时需要的各种资源的精华帖,方便查阅
    Tasker 正则表达式测试器
    支持Tasker控制的app合集
    Tasker文件夹说明
  • 原文地址:https://www.cnblogs.com/Forgenvueory/p/13396414.html
Copyright © 2011-2022 走看看