1、题目

给定3个参数, n n n, m m m, k k k

表示怪兽有 n n n 滴血,等着英雄来砍自己

英雄每一次打击,都会让怪兽流失 [0 ~ m m m] 的血量

到底流失多少?每一次在 [0 ~ m m m] 上等概率的获得一个值

求 k k k 次打击之后,英雄把怪兽砍死的概率。

2、思路

本题为字节跳动北美原题。

样本对应模型,因为 n n n 是样本,怪兽0~n滴血; k k k 是样本,可以砍 0~k 刀,二维的,因为 m m m 不变。

英雄每次打击都有 ( m + 1 ) (m+1) (m+1) 种可能,所以每次打击都是 ( m + 1 ) (m+1) (m+1) 次展开,所以总共的可能性是 ( m + 1 ) k (m+1)^k (m+1)k。

枚举每种情况下把怪兽砍死的点数,点数之后 / ( m + 1 ) k (m+1)^k (m+1)k 就是经过 k k k 次打击后把怪兽砍死的概率。

注意:即便在 k k k 次之前砍死了也要继续砍(鞭尸),不剪枝。

  • 暴力递归版本
public class KillMonster {public static double right(int n, int m, int k) {if (n < 1 || m < 1 || k < 1) return 0;long all = (long)Math.pow(m + 1, k); //总的情况数long kill = process(k, m, n); //砍死的情况数return (double)((double)kill / (double)all);}// 怪兽还剩 hp 点血// 每次伤害在 0~m 范围上// 还有 times 次可以打击// 返回砍死的情况数public static long process(int times, int m, int hp) {if (times == 0) {return hp <= 0 ? 1 : 0;}if (hp <= 0) { //血量小于0的时候,获得的生成点就是 (m + 1) ^ (还剩的打击次数)return (long) Math.pow(m + 1, times);}long ways = 0;for (int i = 0; i <= m; i++) {ways += process(times - 1, m, hp - i);}return ways;}
}
  • 动态规划版本

由递推推导 dp 表的时候,如果发现等规模的 dp 表不好构建时(比如出现负数的情况),就总结出一些剪枝的策略进行补进递归中,比如递归中的 hp <= 0 的判断。

//递归函数中可变参数hp(范围0~n)和times(0~k),所以二维表
public class KillMonster {public static double right(int n, int m, int k) {if (n < 1 || m < 1 || k < 1) return 0;long all = (long)Math.pow(m + 1, k); //总的情况数long[][] dp = new int[k + 1][n + 1];//递归函数中 times 依赖于 times -1,dp[0][0] = 1; //第0行的第0列位置为1,其他位置都是0for (int times = 1; times <= k; times++) {dp[times][0] = (long)Math.pow(m + 1, times); //填0列的值for (int hp = 1; hp <= n; hp++) {long ways = 0;for (int i = 0; i <= m; i++) { //枚举行为//假设还剩3次可以打击,但是此时怪兽血量已经<=0,依然继续打击,每次打击依然是(m+1) 次展开,那么还有 (m+1)^3 个生存点// hp - i可能小于0,所以在前面进行判断//ways += dp[times - 1][hp - i];if (hp - i >= 0) {ways += dp[times - 1][hp - i];} else { //血量<0ways += (long) Math.pow(m + 1, times - 1);}}dp[times][hp] = ways;}}long kill = dp[k][n]; //砍死的情况数return (double)((double) kill / (double) all);}
}

可见确定二维表的值的时有个枚举行为,观察临近位置(观察动态规划中的枚举行为)。

假设 dp[5][10] 表示的是还有 5 次打击,怪兽还剩 10 点血,而每次打击血量流失范围为 0~3,那么 dp[5][10] 依赖于 dp[4][10]dp[4][9]dp[4][8]dp[4][7] (即dp[4][10...7]),而 dp[5][11] 依赖于 dp[4][11]dp[4][10]dp[4][9]dp[4][8]

那么 dp[5][11] = dp[5][10] + dp[4][11] - dp[4][7]dp[4][11...8])。可见依赖的变化范围是和 m m m 相关的。

抽象可得,那么知道了 dp[i][j - 1] 的值如何得到 dp[i][j] 的值呢?

dp[i][j] = dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1 - m]

所以可以进行优化。

  • 动态规划优化版本(斜率优化)
public class KillMonster {public static double right(int n, int m, int k) {if (n < 1 || m < 1 || k < 1) return 0;long all = (long)Math.pow(m + 1, k); //总的情况数long[][] dp = new int[k + 1][n + 1];//递归函数中 times 依赖于 times -1,dp[0][0] = 1; //第0行的第0列位置为1,其他位置都是0for (int times = 1; times <= k; times++) {dp[times][0] = (long)Math.pow(m + 1, times); //填0列的值for (int hp = 1; hp <= n; hp++) {dp[times][hp] = dp[times][hp - 1] + dp[times - 1][hp];if (hp - 1 - m >= 0) {dp[times][hp] -= dp[times - 1][hp - 1 - m];} else { //这种情况是剩的血量 < 血量消耗范围最大值时,如dp[3][3], m = 5//那么dp[3][3] = dp[2][3...-2]//dp[3][4] = dp[2][4...-1]//则dp[3][4] = dp[3][3] + dp[2][4] - dp[2][-2], 而 dp[2][-2] 的情况是由公式决定的dp[times][hp] -= Math.pow(m + 1, times - 1);}}}long kill = dp[k][n]; //砍死的情况数return (double)((double) kill / (double) all);}
}

动态规划:砍死怪兽的概率相关推荐

  1. 动态规划-打败怪兽的概率(java)

    打败怪兽的概率 打败怪兽的概率 暴力递归 代码演示 动态规划 代码演示 动态规划专题 打败怪兽的概率 给定3个参数,N,M,K 怪兽有N滴血, 等着英雄来砍自己 英雄每一次打击, 都会让怪兽流失[0~ ...

  2. 2022-11-09:给定怪兽的血量为hp 第i回合如果用刀砍,怪兽在这回合会直接掉血,没有后续效果 第i回合如果用毒,怪兽在这回合不会掉血, 但是之后每回合都会掉血,并且所有中毒的后续效果会叠加 给

    2022-11-09:给定怪兽的血量为hp 第i回合如果用刀砍,怪兽在这回合会直接掉血,没有后续效果 第i回合如果用毒,怪兽在这回合不会掉血, 但是之后每回合都会掉血,并且所有中毒的后续效果会叠加 给 ...

  3. 给出3个参数,N,M,K,怪兽有N滴血,等着英雄来砍自己,英雄每一次打击,都会让怪兽流失[0~M]的血量,到底流失多少?每一次在[0~M]上等概率的获取一个值,求K次打击之后,英雄把怪兽砍死的概率

    问题描述:给出3个参数,N,M,K,怪兽有N滴血,等着英雄来砍自己,英雄每一次打击,都会让怪兽流失[0~M]的血量,到底流失多少?每一次在[0~M]上等概率的获取一个值,求K次打击之后,英雄把怪兽砍死 ...

  4. 负载大逃亡:四十二路怪兽联军及七条逃生法则(很喜欢)

    负载大逃亡:四十二路怪兽联军及七条逃生法则 摘要:横向扩展与纵向扩展帮助我们处理了大量的高负载问题,然而优秀的程序设计仍然是不可忽视的.一个有设计缺陷的应用程序在低负载情况下可能表现不出来,然而随着负 ...

  5. (转)负载大逃亡:四十二路怪兽联军及七条逃生法则

    转:http://www.csdn.net/article/2013-03-21/2814590-load-increase-42-monsters-7-life-save 摘要:横向扩展与纵向扩展帮 ...

  6. Java-打怪兽趣味小游戏(附效果图)

    注:此项目主要用来巩固面向对象以及父类子类继承这一块的知识,其中涉及循环以及随机函数的灵活运用 一.定义父类(怪兽类)和父类(玩家类) 1.怪兽类的属性和方法 属性:攻击力,生命值: 方法:怪兽普通攻 ...

  7. (转)算法帝国:华尔街交易怪兽的核武器缔造史

    算法帝国:华尔街交易怪兽的核武器缔造史 华尔街见闻 2017-02-01 访问量 570 1980年华尔街的黑客生涯:天时地利 http://wallstreetcn.com/node/287583 ...

  8. 2018-2-22 《啊哈,算法》再练习广度优先搜索,题:炸怪兽, 2-23改用深度优先搜索。宝岛探险(广度,深度,及地图着色)2-24水管工游戏,2-25测试水管工代码...

    2小时. 先是是纠错,通过对代码运行过程的测试.发现是变量打错.以及录入地图❌. 重构练习题,改使用while..end代替for in. ⚠️ : 在while(k <= n)中如果用到nex ...

  9. 算法期中1007. 怪兽训练 (找出有向图中所有的强连通分量的Kosaraju算法)

    Description 贝爷的人生乐趣之一就是约战马会长. 他知道马会长喜欢和怪兽对决,于是他训练了N只怪兽,并对怪兽用0到N-1的整数进行编号. 贝爷训练怪兽的方式是让它们一对一互殴. 两只怪兽互殴 ...

最新文章

  1. OpenCV 【十九】图像金字塔/基本的阈值操作/实现自己的线性滤波器
  2. UVA1025 城市里的间谍 A Spy in the Metro(2003 ICPC world final)(DAG上DP)
  3. E - Another Postman Problem FZU - 2038
  4. 11、oracle数据库下的事务和触发器
  5. 召唤新一代超参调优开源新神器,集十大主流模块于一身
  6. 在队列同步器中,同步队列为什么是双向链表,而等待队列是单链表?
  7. Windows游戏编程大师技巧(第2版)
  8. matlab灵敏度分析操作,灵敏度分析 使用MATLAB编写.doc
  9. 用matlab s函数 阶梯,Matlab S函数使用介绍
  10. paypal支付(Java)
  11. 企业域名注册手续_如何注册域名以及ICP备案
  12. 携手推进国产化发展,未来智安与麒麟软件完成兼容互认证
  13. java使用poi操作ppt(导入,导出,读取,添加,拼接,替换文本,页面排序)
  14. 懒惰、急躁和傲慢(Laziness, Impatience and hubris)
  15. Node.js躬行记(18)——半吊子的可视化搭建系统
  16. 南京大学计算机课程表,南大课表新鲜出炉,哪个专业课程最多?
  17. 第四届【强网杯】主动
  18. CSS——粘性定位(sticky)
  19. Linphone android去电增加自定义SIP消息头的流程分析
  20. 认知结构(C# Struct)

热门文章

  1. DSP TMS320F280049之数模转换器DAC(寄存器版)
  2. 搜集统计年鉴,超级简单的方法
  3. html怎么实现地球自转,纯CSS3实现地球自转的教程
  4. 手机软件测试系统,软件测试之手机软件系统测试用例设计方法.doc
  5. log4j每天/每小时/每分钟生成多个日志文件
  6. 在保研中脱颖而出的个人简历模板
  7. 插入参考文献时杂志缩写名字混乱问题一次解决 - 修改style是没用的
  8. 使用VS 2019编译Mitsuba渲染器
  9. cf919的ABC(太咸nowatashi)
  10. 利用C语言绘制余弦函数