消灭最终BOSS
题目来源:华为机试题
某游戏中,玩家的任务是杀死终极BOSS。BOSS和玩家战斗方式为回合制,玩家先发动进攻。BOSS的攻击方式为:普通攻击和暴击,每4回合普通攻击的下一回合攻击为暴击。BOSS的普通攻击力为10点HP,暴击时的攻击力为普通攻击的3倍。玩家的攻击方式为:普通攻击和魔法攻击。玩家的普通攻击为17点HP,魔法攻击为60点HP。使用魔法攻击时需要消耗10点魔法值,魔法值来源有两种:初始魔法量和回合内选择魔法恢复,魔法恢复速度为4点/回合,魔法恢复回合内无法发动攻击。每轮回合开始时,玩家可以选择:普通攻击、魔法攻击或恢复魔法三种行动方式之一。现已知玩家的HP和初始魔法量,BOSS的HP,编写程序,求玩家战胜BOSS的最小回合数。
1 Sec
100 MByte
输入三个整数HP(0<HP1<=10000),MP(0<MP<=1000),HP2(0<HP2<=10000),分别为玩家的HP、玩家的初始魔法量和BOSS的HP。
若玩家可以战胜BOSS输出战胜BOSS的最小回合数,否则输出-1.
100 20 100
2
无
思路:由于本人是刚接触编程不久的菜鸟,目前还不会使用动态规划和贪心算法,所以用现有的水平分析一下这道题。
1. 如果MP(魔法量)>=10,我们总是可以选择魔攻造成60点伤害;
2. 如果6<=MP<10,BOSS血量高于34,选择魔回+魔攻造成60点伤害;
3. 如果2<=MP<6,BOSS血量高于51,选择魔回*2+魔攻造成60点伤害;
4. 如果MP<2,此时需要综合考虑,回魔*5+魔攻*2可造成120点伤害,同样回合数普攻*7可造成119点伤害,所以,如果BOSS血量不高于119,只进行普攻就可以得到最优方案,如果BOSS血量高于119,选择回魔*5+魔攻*2可以造成更多伤害。
因此,我的代码如下:
#include <stdio.h>
int main()
{
int playerhp, playermp, bosshp;
while(scanf("%d%d%d", &playerhp, &playermp, &bosshp) != EOF) {
int countbossdeath = 0, countplayerdeath = 0;
while(bosshp > 0) {
if(playermp >= 10) {
bosshp -= 60;
playermp -= 10;
countbossdeath++;
} else if(playermp >= 6 && playermp < 10) {
if(bosshp <= 34) {
countbossdeath += (bosshp + 16) / 17;
bosshp -= 34;
} else {
bosshp -= 60;
playermp -= 6;
countbossdeath += 2;
}
} else if(playermp >= 2 && playermp < 6) {
if(bosshp <= 51) {
countbossdeath += (bosshp + 16) / 17;
bosshp -= 51;
} else {
bosshp -= 60;
playermp -= 2;
countbossdeath += 3;
}
} else {
if(bosshp <= 119) {
countbossdeath += (bosshp + 16) / 17;
bosshp -= 119;
} else {
bosshp -= 120;
countbossdeath += 7;
}
}
}
while(playerhp > 0) {
if(countplayerdeath != 4)
playerhp -= 10;
else
playerhp -= 30;
countplayerdeath++;
}
if(countplayerdeath >= countbossdeath)
printf("%d\n", countbossdeath);
else
printf("-1\n");
}
return 0;
}
经过大神指导,才明白以上代码属于贪心算法,现在使用动态规划解决问题,代码如下:
#include <stdio.h>
int bossattack(int hp)
{
int ret, rem;
ret = hp / 70 * 5; // BOSS每5回合造成70点伤害
rem = (hp % 70 + 9) / 10;
if(rem > 4)
ret += 5;
else
ret += rem;
return ret;
}
int record[1001][10001];
int playerattack(int mp, int hp)
{
int r1, r2;
if(hp <= 0)
return 0;
if(record[mp][hp] != -1)
return record[mp][hp];
if(mp >= 10)
return record[mp][hp] = 1 + playerattack(mp-10, hp-60);
else {
r1 = 1 + playerattack(mp+4, hp);
r2 = 1 + playerattack(mp, hp-17);
return record[mp][hp] = (r1 < r2 ? r1 : r2);
}
}
int main()
{
int playerhp, playermp, bosshp;
while(scanf("%d%d%d", &playerhp, &playermp, &bosshp) != EOF) {
int i, j, bossdead, playerdead;
for(i = 0; i < 1001; i++)
for(j = 0; j < 10001; j++)
record[i][j] = -1;
playerdead = bossattack(playerhp);
bossdead = playerattack(playermp, bosshp);
if(playerdead < bossdead)
printf("-1\n");
else
printf("%d\n", bossdead);
}
return 0;
}