“趣味”or“烧脑”算法 之 王子救公主
| 题引
相信大部分人童年都玩过大富豪这样一类的棋,棋格上面有加多少分,减多少分等等设置,比赛最终谁的分值最多(类似下面这个棋盘)
| 正题
设置小游戏为一个二维矩阵,
王子位于左上角,公主位于右下角,
每个单元格将会出现怪物或者补给
怪物:打斗减血(负数表示,且为整数)
补给:加血(正数表示,且为整数)
王子只能往下或者往右前进,
如果王子血量为0或负数,即为拯救失败,
求王子至少需要多少初始血量,才能抵达公主?
最优解: -2 — -3 — 3 — 1 — -5 需要初始血量为7
| 分析
先分析题目的重点:
- 只能往右或着往下前进
- 任意步只要血量掉0即失败(也就意味每步结束后血量至少保持1点)
- 每步可能加血、减血,或者不变(为0时)
分析完重点,来看一些场景
看完3个小场景后,按常规思路,总结一个小规律
往下往右的时候,判断下和右的大小前进
那么这个结论是不是正确的呢,再来看下面一个场景…
按照上面总结的规律,得出这样的结论,如果细心的去计算的话,发现并不是最优解,虽然第一步的时候-3,但是+5之后,立马又回血了,正确的最优解如下:
至此,说明上面的小规律总结并不成立,那么就说明从正面打通思路就不行了,那么就逆向思维看看是否有解决办法?
再分析:
从后往前计算,计算当我达到这步的时候,应该需要多少血量(为了方便计算,我们计算每步的临界值,即到达这步血量为0,最终结果+1即可)
以场景4为例:
计算到“王子”位置时,结果为2,表示王子位置出发,必须至少需要2+1=3血量
总结一下:
- 逆向思维倒推,从后往前计算每步至少血量
- 最右和最下边,可通过下面或后面的值,再与当前棋格的值计算可得出至少血量
- 中间部分可通过相邻的右边和下边值判断出,再与当前棋格的值计算可得出至少血量
计算顺序逻辑图如下:
|编码
分析了这么多,我们按照分析思路去编码实现(小伙伴们可以自己先尝试编码看看)
/*** @author yanghao* @version LeetCode174Test.java, v 0.1 2019-11-12 16:43*/
public class LeetCode174Test {public static void main(String[] args) {LeetCode174Test test = new LeetCode174Test();/*int[][] dungeon = new int[3][3];dungeon[0] = new int[]{-2, -3, 3};dungeon[1] = new int[]{-5, -10, 1};dungeon[2] = new int[]{10, 30, -5};*//*int[][] dungeon = new int[3][3];dungeon[0] = new int[]{1,-3,3};dungeon[1] = new int[]{0,-2,0};dungeon[2] = new int[]{-3,-3,-3};*/int[][] dungeon = new int[3][3];dungeon[0] = new int[]{1, -3, 5};dungeon[1] = new int[]{0, -5, 0};dungeon[2] = new int[]{-3, -3, 1};/*int[][] dungeon = new int[2][2];dungeon[0] = new int[]{2, 1};dungeon[1] = new int[]{1, -1};*//*int[][] dungeon = new int[2][2];dungeon[0] = new int[]{0, 5};dungeon[1] = new int[]{-2, -3};*//*int[][] dungeon = new int[2][1];dungeon[0] = new int[]{2};dungeon[1] = new int[]{1};*//*int[][] dungeon = new int[2][1];dungeon[0] = new int[]{1};dungeon[1] = new int[]{-1};*//*int[][] dungeon = new int[2][3];dungeon[0] = new int[]{3, -20, 30};dungeon[1] = new int[]{-3, 4, 0};*//*int[][] dungeon = new int[3][1];dungeon[0] = new int[]{1};dungeon[1] = new int[]{-2};dungeon[2] = new int[]{1};*//*int[][] dungeon = new int[1][2];dungeon[0] = new int[]{0, 0};*/System.out.println(test.leetCode174(dungeon));}public int leetCode174(int[][] dungeon) {int x = dungeon[0].length;int y = dungeon.length;if (dungeon == null || x == 0 || y == 0) {return 0;}//定义一个矩阵存储每格需要的血量,从后往前推算每格最少需要多少血量int[][] blood = new int[y][x];//填充最后一格blood[y - 1][x - 1] = Math.max(0, -dungeon[y - 1][x - 1]);//定义所需最少血量int lowBlood = 0;//填充最后一行for (int i = x - 2; i >= 0; i--) {lowBlood = blood[y - 1][i + 1] - dungeon[y - 1][i];blood[y - 1][i] = Math.max(0, lowBlood);}//填充最后一列for (int i = y - 2; i >= 0; i--) {lowBlood = blood[i + 1][x - 1] - dungeon[i][x - 1];blood[i][x - 1] = Math.max(0, lowBlood);}//填充中间部分for (int i = x - 2; i >= 0; i--) {for (int j = y - 2; j >= 0; j--) {lowBlood = Math.min(blood[j][i + 1], blood[j + 1][i]) - dungeon[j][i];blood[j][i] = Math.max(0, lowBlood);}}return blood[0][0] + 1;}}
|赠语
学习算法,思想很重要,要学会突破常规思路
(本题尝试了很多解决思路,这个算是比较优的解决办法,当然还可以通过其他方式去实现,小伙伴们尽情发挥自己的大脑吧,本题目来自LeetCode 174题,题目为了易懂,稍作精简改编)
“趣味”or“烧脑”算法 之 王子救公主相关推荐
- java王子救公主的游_计蒜客 王子救公主(DFS)
一天,蒜头君梦见自己当上了王子,但是不幸的是,自己的公主被可恶的巫婆抓走了.于是蒜头君动用全国的力量得知,自己的公主被巫婆抓进一个迷宫里面.由于全国只有蒜头君自己可以翻越迷宫外的城墙,蒜头君便自己一人 ...
- DFS练习——王子救公主
一天,蒜头君梦见自己当上了王子,但是不幸的是,自己的公主被可恶的巫婆抓走了.于是蒜头君动用全国的力量得知,自己的公主被巫婆抓进一个迷宫里面.由于全国只有蒜头君自己可以翻越迷宫外的城墙,蒜头君便自己一人 ...
- 计蒜客:王子救公主---dfs
题目描述: 一天,蒜头君梦见自己当上了王子,但是不幸的是,自己的公主被可恶的巫婆抓走了.于是蒜头君动用全国的力量得知,自己的公主被巫婆抓进一个迷宫里面.由于全国只有蒜头君自己可以翻越迷宫外的城墙,蒜头 ...
- 【DFS题型九/双向DFS】王子救公主
题目描述: 一天,蒜头君梦见自己当上了王子,但是不幸的是,自己的公主被可恶的巫婆抓走了.于是蒜头君动用全国的力量得知,自己的公主被巫婆抓进一个迷宫里面.由于全国只有蒜头君自己可以翻越迷宫外的城墙,蒜头 ...
- 计蒜客 王子救公主 dfs
题意:如上,注意王子有可能跨越墙,前提使正好挨着墙. 思路:dfs王子和公主,开一个三维数组分别用vis[x][y][0],vis[x][y][1]标记王子和公主走到的点. 若存在二点相交即(vis[ ...
- 【深度优先搜索】计蒜客:王子救公主
思路:用两次深度优先搜索,数组vis1标记王子可能到达的点,数组vis2标记公主可能到达的点: 如果两个数组有重复的标记的坐标,那么王子可以救出公主 !标记所有可能情况的深度优先搜索不需要回溯! 如果 ...
- 王子救公主 (计蒜客)一道简单DFS
蓝桥杯不能粘贴 只能截图.. 这道题目很简单,主要想清楚 只要存在王子和公主都能到达的点,王子就能救出公主(此时必定有一个时刻可以让他们相遇) #include <bits/stdc++.h& ...
- 王子救公主(DFS)
样例输入 1 8 w....#.g 样例输出 yes 解题思路: 两次搜索: 1.第一次对王子进行搜索,标记王子能到达的所有点. 2.第二次对公主进行搜索,如果公主能到达王子标记过的点,那么说明王子可 ...
- 【DFS专题训练】王子救公主 C++程序题
题目描述 王子走两步,公主走一步,遇到#不能走,他们能否碰上 输入 1 8 w-#.g 输出 yes 思路 王子深搜一次记录走过的地方,公主深搜一次记录走过的地方,如果都走过就返回yes #inclu ...
最新文章
- 《iOS 6核心开发手册(第4版)》——2.1节UIControl类
- 樱桃键盘驱动在哪下_手感还是信仰?樱桃Cherry MX8.0与MC 8.1军火箱键鼠套装体验点评...
- 东南大学王萌 | “神经+符号”学习与多模态知识发现
- 利用国内镜像加快pip下载速度和成功率
- OPTIRRA研究: TNF拮抗剂维持期优化减量方案[EULAR2015_SAT0150]
- 分解原理_葛兰维均线的数学拟合原理--傅立叶函数的分解的应用
- 一个程序员的书法学习之路-法帖篇
- Git 64位安装包下载
- java号码池_Java常量池详解
- 收银机多少钱一台推荐科脉系统_收银系统多少钱一套?常用收银系统价格大盘点...
- 维生素D与肠道菌群的互作
- 两个服务器微信消息模板发不出去,小程序模板消息调用send大部分情况下发送不出去,但有时又可以发送,什么情况?...
- 用Python做一个久坐提醒小助手
- c# NPOI 导出Excel 冻结窗格
- 九爷带你了解 Tomcat 优化
- matlab下载光盘刻录,最新的linux下dvd刻录软件,支持DVD+RW、DVD-RW光盘刻录。
- Java打印乘法口诀表(任何数)
- html加载背景图片
- 关于25Qxx踩坑总结(无法写入)
- “以简驭繁”打造卓越校园网 ——锐捷助力西安理工大学校园网建设
热门文章
- C++ malloc、智能指针、类型转换等(三)
- GlusterFS 配置及使用 二 :Windows挂载GlusterFS
- 加州大学圣塔芭芭拉分校计算机排名,加州大学圣塔芭芭拉分校世界排名及专业排名汇总(QS世界大学排名版)...
- 分治法典型体现之快速排序(一遍单项扫描)
- 厉害了:杀毒软件卡巴斯基将推出二次元萌妹形象,C92见
- MySQL数据库基本操作---DDL
- 单相电机正反转接线图_单相电机正反转接线图
- 【PaperReading】情感人的互联网:通过视听信号实现跨文化的可持续情感计算
- 免费提供一个完整股票分析软件源码(包含开发文档)
- 终结者2进去后显示天网服务器,《终结者2:审判日》天网觉醒秘测开服公告