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];
      }
    };
    
  • 相关阅读:
    java Activiti 工作流引擎 SSM 框架模块设计方案
    自定义表单 Flowable 工作流 Springboot vue.js 前后分离 跨域 有代码生成器
    数据库设计的十个最佳实践
    activiti 汉化 stencilset.json 文件内容
    JAVA oa 办公系统模块 设计方案
    java 考试系统 在线学习 视频直播 人脸识别 springboot框架 前后分离 PC和手机端
    集成 nacos注册中心配置使用
    “感恩节 ”怼记
    仓颉编程语言的一点期望
    关于System.out.println()与System.out.print("\n")的区别
  • 原文地址:https://www.cnblogs.com/Forgenvueory/p/13396414.html
Copyright © 2011-2022 走看看