地下城游戏

  • 题目描述:
    • 分析1:
      • 代码1:
    • 分析2:
      • 代码2:
  • 注意事项:

题目描述:

一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快到达公主,骑士决定每次只向右或向下移动一步。
编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。

分析1:

刚开始拿到这个题的时候,我第一时间想到的就是用动态数组的方法,定义一个dp[i][j],表示骑士到i,j位置时的血量,我发现这个题最终求的是从(0,0)位置到(m,n)位置的最小初始值,也就是说我们要求从(0,0)到(m,n)经历过的最小生命值,那么这样定义就得不到我们想要的数据,然后我想定义两个dp1[i][j]表示骑士到i,j位置时的血量,dp2[i][j]表示从(0,0)到(i,j)经历过的最小生命值,我们希望的是dp1尽可能大,dp2尽可能小。我编程了一会儿发现dp1与dp2并不能形成一定的关系—dp1[i][j]走的路径不一定是dp2[i][j]走的路径,所以无法推导出递推公式,也有可能是我能力问题无法推导出来公式。

因此,如果按照从左上往右下的顺序进行动态规划,我们无法直接确定到达 (m,n) 的方案,因为有两个重要程度相同的参数同时影响后续的决策。也就是说,这样的动态规划是不满足「无后效性」的。

所以我们要从右下往左上的顺序进行动态规划,令 dp[i][j]dp[i][j] 表示从坐标 (i,j)到终点所需的最小初始值。换句话说,当我们到达坐标 (i,j)时,如果此时我们的路径和不小于 dp[i][j],我们就能到达终点。
dp数组定义
dp[i][j]表示从(i,j)到(m,n)的最小初始值
递推公式
dp[i][j] = max(1,min(dp[i+1][j]-nums[i][j],dp[i][j+1]-nums[i][j])) //初始值一定要大于等于1
临界值初始化
当 i=n-1或者 j=m-1 时,dp[i][j] 转移需要用到的 dp[i][j+1] 和 dp[i+1][j] 中有无效值,因此代码实现中给无效值赋值为极大值。特别地,dp[n−1][m−1] 转移需要用到的 dp[n-1][m]和 dp[n][m-1] 均为无效值,因此我们给这两个值赋值为 1。

代码1:

int calculateMinimumHP(vector<vector<int>>& dungeon) {   int m = dungeon.size(), n = dungeon[0].size();vector<vector<int>> dp(m, vector<int>(n));if(dungeon[m-1][n-1] >= 0){dp[m-1][n-1] = 1;}else{dp[m-1][n-1] = 1-dungeon[m-1][n-1];}for (int i = m-1 ; i >= 0; --i) {for (int j = n-1 ; j >= 0; --j){if(i == m-1 && j == n-1) continue;if(i+1 < m && j+1 < n){int minn = min(dp[i+1][j],dp[i][j+1]);if(dungeon[i][j] - minn >= 0 ){dp[i][j] = 1;}else{dp[i][j] = -(dungeon[i][j] - minn);}}else if(i+1 < m){int minn = dp[i+1][j];if((dungeon[i][j] - minn) >= 0 ){dp[i][j] = 1;}else{dp[i][j] = dungeon[i][j] - minn;dp[i][j] *=-1;}}else if(j+1 < n){int minn = dp[i][j+1];if(dungeon[i][j] - minn >= 0 ){dp[i][j] = 1;}else{dp[i][j] = dungeon[i][j] - minn;dp[i][j] *=-1;}}}}return dp[0][0];}

因为 if(i == m-1 && j == n-1) continue; 写成了break,改了一个多小时的BUG…

分析2:

因为是反过来逆推,所以我们应该要想到递归算法,此题还可以用DFS的方法–求(0,0)到(m,n)的最小生命初始值可以转换成求min((1,0)到(m,n)与(0,1)到(m,n)的最小生命初始值),因此这是一个显而易见的递归题

代码2:

vector<vector<int>> memo;// 定义记忆化数组int calculateMinimumHP(vector<vector<int>>& dungeon) {memo.resize(dungeon.size());for(int i=0;i<memo.size();i++){memo[i].resize(dungeon[0].size());}return dfs(dungeon, dungeon.size(), dungeon[0].size(), 0, 0);//从(0,0)坐标开始}int dfs(vector<vector<int>>& dungeon, int m, int n, int i, int j) {// 到达终点,递归终止。if (i == m - 1 && j == n - 1) {if(dungeon[m-1][n-1] >= 0) return 1;else{return 1-dungeon[m-1][n-1];}}// 如果memo数组中有值,直接取出并返回,不进行后续的搜索。if (memo[i][j] > 0) {return memo[i][j];}//向右搜+向下搜int minRes = 0;if (i == m - 1) ///只能向右搜{minRes =  max(dfs(dungeon, m, n, i, j + 1) - dungeon[i][j], 1);} else if (j == n - 1) //只能向下搜{minRes = max(dfs(dungeon, m, n, i + 1, j) - dungeon[i][j], 1);} else //向下与向右搜{int minn = min(dfs(dungeon, m, n, i + 1, j), dfs(dungeon, m, n, i, j + 1));minRes = max(minn - dungeon[i][j], 1);}// 将结果存入memo数组return memo[i][j] = minRes;}

注意事项:

注意要用一个memo记忆数组来存放计算过的值,否则时间复杂度不能通过此题

Leetcode--地下城游戏相关推荐

  1. LeetCode 地下城游戏

    一些恶魔抓住了公主(P)并将她关在了地下城的右下角.地下城是由 M x N 个房间组成的二维网格.我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主. 骑士的初始 ...

  2. leetcode 思路——64. 最小路径和——174. 地下城游戏

    leetcode 思路--64. 最小路径和--174. 地下城游戏 64. 最小路径和 174. 地下城游戏 64. 最小路径和 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角 ...

  3. [算法]LeetCode每日一题--174. 地下城游戏(Java)

    DailyChallenge 174. 地下城游戏 Hard20200712 Description 一些恶魔抓住了公主(P)并将她关在了地下城的右下角.地下城是由 M x N 个房间组成的二维网格. ...

  4. ​LeetCode刷题实战174:地下城游戏

    算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试.所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 ! 今天和大家 ...

  5. LeetCode 174.地下城游戏

    LeetCode 174.地下城游戏 一些恶魔抓住了公主(P)并将她关在了地下城的右下角.地下城是由 M x N 个房间组成的二维网格.我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城 ...

  6. LeetCode 174. 地下城游戏 | Python

    文章目录 174. 地下城游戏 题目 解题思路 代码实现 实现结果 欢迎关注 174. 地下城游戏 题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/ ...

  7. leetcode题库174 地下城游戏

    地下城游戏 一些恶魔抓住了公主(P)并将她关在了地下城的右下角.地下城是由 M x N 个房间组成的二维网格.我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主. ...

  8. Java实现 LeetCode 174 地下城游戏

    174. 地下城游戏 一些恶魔抓住了公主(P)并将她关在了地下城的右下角.地下城是由 M x N 个房间组成的二维网格.我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来 ...

  9. leetcode:174.地下城游戏

    地下城游戏 难度 困难 一些恶魔抓住了公主(P)并将她关在了地下城的右下角.地下城是由 M x N 个房间组成的二维网格.我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔 ...

  10. leetcode174. 地下城游戏(java)

    地下城游戏 leetcode174. 地下城游戏 题目描述 动态规划 解题思路 代码 动态规划专题 leetcode174. 地下城游戏 来源:力扣(LeetCode) 链接:https://leet ...

最新文章

  1. 查询Sqlserver数据库死锁的一个存储过程
  2. 每日一皮:阅读软件许可协议让你想到了什么?
  3. 大学计算机课算绩点吗,南京大学GPA是如何计算的
  4. setBackgroundDrawable和setBackgroundColor的用法(转)
  5. fast.ai 深度学习笔记:第一部分第一课
  6. mongdb mysql geospatial 比较_MongoDB的地理位置查询,以及和mysql的使用对比
  7. Makefile中的变量
  8. 数据可视化----我在寻找一款类似vfp或是access这样自带可视化风格的数据库或是键盘数据库...
  9. js console 输出到文件_Node.js核心入门
  10. 郎朗钢琴课独家上线知乎 手把手带你开启钢琴之路
  11. PHP spl_autoload_register()函数的一些见解
  12. CentOS7中安装PostgreSQL客户端
  13. DJ音乐盒-专注DJ
  14. Hutool 导出excel并合并单元格
  15. 装修、家具设计标准尺寸参考
  16. linux中ess33没有IP地址问题
  17. 教你如何理解DSP、SSP、RTB、ADX名词
  18. 网易互娱人工智能工程师笔试题
  19. APP漏洞扫描器之本地拒绝服务检测详解
  20. 数学计算机软件推荐,科学计算器软件有哪些?2020好用的科学计算器推荐

热门文章

  1. FFmpeg视频的旋转rotate
  2. 中M22春C、Java入门练习-7.1
  3. 软件测试--边界值分析法
  4. angularjs中的依赖注入
  5. (layui)点击加号添加电话输入框,点击减号,电话输入框删除
  6. html如何避免360自动填充账号密码,解决浏览器会自动填充密码的问题
  7. 前端关于百度地图JavaScript Api 使用
  8. html表单模板属性,HTML5超酷响应式表单美化模板插件
  9. Java多线程书籍推荐
  10. oracle数据库常见故障及灾难情况分析