牛牛是励志成为世界第一宝可梦大师的宝可梦训练家。现在他遇到了一个强劲的野生宝皮卡丘,野生宝皮卡丘的生命值是HP,攻击力是ACK,牛牛召唤的宝可梦是杰尼龟。杰尼龟的生命值是HP2,攻击力是ACK2,除此之外身为训练家还可以给宝可梦吃药让他满血复活(吃药发生在双方发动攻击之前,并且吃药一方不得在本回合发动攻击)。
牛牛想知道他最少多少回合才能能打败野生宝皮卡丘?
因为皮卡丘会电光一闪,所以皮卡丘总是比杰尼龟先发动攻击。若能成功击败野生皮卡丘则返回最少回合数,否则返回-1。
8,3,8,1
14
至少需要14回合战胜野生皮卡丘
1,1,1,1
-1
皮卡丘先出招就直接打死了杰尼龟,所以无法获胜
首先是特判,如果初始时候皮卡丘攻击力大于等于杰尼龟的生命值,那么杰尼龟一直处于死亡复活的死循环中,直接返回 -1
接下来,以例子(15 3 10 2)说明:
杰尼龟 皮卡丘 10 -> 7 15 -> 13 7 -> 4 13 -> 11 4 -> 1 11 -> 9 1 -> 10 -> 7 9 7 -> 4 9 -> 7 4 -> 1 7 -> 5 1 -> 10 -> 7 5 7 -> 4 5 -> 3 4 -> 1 3 -> 1 1 -> 10 -> 7 1 7 -> 4 1 -> GG
没有直接返回,说明杰尼龟抗住了第一次攻击,并且发起了一次反击,皮卡丘的生命值降低,变为 HP = HP - ACK2
。
所以,可以声明 result
记录一共需要的回合数,同时初始化 result
为 1,表示第一次攻击。
然后,这里有几个点需要特判:
再来看除第一次攻击之外的其余的部分,容易得到这部分存在循环(也就是 1 -> 7 -> 4 -> 1 -> ···):
countOfCycle = (HP2 - 1) / ACK
ackOfCycle = (countOfCycle - 1) * ACK2
这样就可以计算出“至少”需要几轮才可以打败皮卡丘,即 basicCount = HP / ackOfCycle
知道了“至少”需要几轮之后,可以将这部分直接接到 result
上,即 result += basicCount * countOfCycle
需要注意的是,计算 basicCount
时默认是向下取整,那么还要判断皮卡丘是否还有血,即 leftHP = HP % ackOfCycle
是否为 0
leftHP
为 0,说明正好结束掉皮卡丘,但是也增加了一次复活,需要减去 leftHP
不为 0,说明皮卡丘还有血,需要计算出还需要几个回合,也就是 result += leftHP / ACK2 + (leftHP % ACK2 == 0 ? 0 : 1)
public long pokemonFight(long HP, long ACK, long HP2, long ACK2) { /* 杰尼龟处于死亡复活的死循环中,不可能发动攻击 */ if (HP2 <= ACK) { return -1; } long result = 1; /* 第一次攻击 */ HP -= ACK2; if (HP <= 0) { /* 皮卡丘被杰尼龟瞬秒,直接返回 1 */ return result; } else if ((HP2 - ACK) <= ACK) { /* 杰尼龟处于死亡复活的死循环中,直接返回 -1 */ return -1; } /* 几个回合是一个循环 */ long countOfCycle = (HP2 - 1) / ACK; /* 每个循环可以贡献的攻击力 */ long ackOfCycle = (countOfCycle - 1) * ACK2; /* 一共需要几轮 */ long basicCount = HP / ackOfCycle; result += basicCount * countOfCycle; /* 这几轮攻击之后,HP 还剩下多少 */ long leftHP = HP % ackOfCycle; if (leftHP == 0) { /* 如果 leftHP 为 0,说明正好够用,并且最后一次不需要复活 */ result -= 1; } else { /* 如果 leftHP 不为 0,说明还有血,但不需要在进行完整的循环 */ result += leftHP / ACK2 + (leftHP % ACK2 == 0 ? 0 : 1); } return result; }
/* 代码比较复杂,逻辑如下: 1. 如果被一击毙命,返回-1 2. 如果被两击毙命,且不能对对手一击毙命,返回-1 3. 除了以上情况,如果可以对对手一击毙命,返回1 4. 除了以上情况,分别计算一下,需要几回合攻击可以让对手血量为0,以及每多少回合需要有一回合吃药, 正确处理取余时的问题即可。 */ class Solution { public: /** * * @param HP long长整型 HP * @param ACK long长整型 ACK * @param HP2 long长整型 HP2 * @param ACK2 long长整型 ACK2 * @return long长整型 */ long long Pokemonfight(long long HP, long long ACK, long long HP2, long long ACK2) { // write code here long long res1, res2, res3; if(ACK >= HP2 || 2*ACK >= HP2 && ACK2 < HP) { return -1; } else if(ACK2 >= HP) { return 1; } else { res1 = HP/ACK2; if(HP%ACK2 != 0) { res1 = res1 + 1; } res2 = (HP2-ACK)/ACK; if(HP2%ACK == 0) { res2 = res2 - 1; } if(res1 < res2 + 1) { res3 = 0; } else { res3 = (res1 - res2 - 1)/res2; if((res1 - res2 - 1)%res2 != 0) { res3 = res3 + 1; } } return res1 + res3; } } };
public long Pokemonfight (long HP, long ACK, long HP2, long ACK2) { // write code here // 预备知识:a / b 取上界可以用 (a - 1)/ b + 1 // 需要攻击次数 ackTimes,取上界 long ackTimes = (HP - 1) / ACK2 + 1; // 每经过 recover 轮需要喝一个大药 long recover = (HP2 - 1) / ACK - 1; // ackTimes <= recover + 1 直接打晕皮卡丘;因为最后一次不喝药可以多打一次 if (ackTimes <= recover + 1) return ackTimes; // recover < 0 会被直接打死,recover == 0 每轮都在喝药,都返回 -1 if (recover <= 0) return -1; // 返回 ackTimes + 喝药次数(取 ackTimes - (recover + 1) / recover 上界) return ackTimes + (ackTimes - recover - 2) / recover + 1; }代码比较简单的,写出来花了好久,脑子真是不够用
class Solution { public: /** * * @param HP long长整型 HP * @param ACK long长整型 ACK * @param HP2 long长整型 HP2 * @param ACK2 long长整型 ACK2 * @return long长整型 */ long long Pokemonfight(long long HP, long long ACK, long long HP2, long long ACK2) { if(ACK >= HP2) return -1; if(ACK2 >= HP) return 1; if(HP2 <= 2*ACK) return -1; return ceil((ceil((double)ACK/ACK2*HP)+1-HP2)/(HP2-ACK-HP2%ACK)) + ceil((double)HP/ACK2); } };
class Solution { public: /** * * @param HP long长整型 HP * @param ACK long长整型 ACK * @param HP2 long长整型 HP2 * @param ACK2 long长整型 ACK2 * @return long长整型 */ long long Pokemonfight(long long HP, long long ACK, long long HP2, long long ACK2) { // write code here if(HP2 <= ACK) return -1; if(HP <= ACK2) return 1; if(HP2 <= 2*ACK) return -1; return ceil((ceil(((double)ACK/ACK2)*HP)+1-HP2)/(HP2 - ACK - HP2%ACK))+ceil(((double)HP/ACK2)); } };
import java.util.*; public class Solution { public long Pokemonfight (long HP, long ACK, long HP2, long ACK2) { if(ACK >= HP2){ //第一回合,先被打,一下被K.O.,打不过 return -1; } if(ACK2 >= HP){ //苟过第一下就能立马反杀,能打过,一局结束 return 1; } if(HP2 - ACK <= ACK){ //回血后没机会打,一直只能回血,打不过 return -1; } long n = HP%ACK2==0? HP/ACK2 : HP/ACK2+1; //皮卡丘被攻击总次数 long m = HP2%ACK==0? HP2/ACK-1 : HP2/ACK; //第一次回血前的攻击次数 long drug = (n-1)%(m-1)==0?(n-1)/(m-1) - 1 : (n-1)/(m-1); //回血次数 return n + drug; } }
function Pokemonfight( HP , ACK , HP2 , ACK2 ) { if(ACK >= HP2 || (ACK2 < HP && ACK*2 >= HP2)) return -1; // 皮卡丘被一次打死 if(HP <= ACK2) return 1; let hp2 = HP2; let hp = HP; // 打死皮卡丘需要多少轮?HP/ACK2+1 let count = HP%ACK2 === 0 ? (HP/ACK2):(HP/ACK2)+1; // 不吃药能撑几轮?HP2/ACK --- 每打几轮需要吃药? let noEat = HP2%ACK === 0 ? (HP2/ACK)-1:(HP2/ACK); if(count < noEat){ count = parseInt(count); return count; }else { // 打死皮卡丘的过程中需要吃多少次药?---吃药过程不能打---而且会被攻击---血量减少一次攻击机会 var eat = parseInt(count-noEat)/parseInt(noEat-1)+1; return parseInt(eat+count); } }
import math class Solution: def Pokemonfight(self , HP , ACK , HP2 , ACK2 ): # write code here #打不过 if ACK>=HP2: return -1 if 2*ACK>=HP2 and ACK2<HP: return -1 #站撸能过 if (math.ceil(HP2/ACK)-1)*ACK2>=HP: return math.ceil(HP/ACK2) #回血锤它 damage_f=(math.ceil(HP2/ACK)-2)*ACK2 if HP%damage_f==0: return (HP/damage_f-1)*(math.ceil(HP2/ACK)-1)+(HP%damage_f)/ACK2 else: return int(HP/damage_f)*(math.ceil(HP2/ACK)-1)+(HP%damage_f)/ACK2