这题我自己感觉是一道很经典的DP题目,对于DP大神来说是非常裸的题,但是对于我这样的DP初学者来说,我觉得是很好的一道入门题。。。收益匪浅。
题意:以魔兽为背景,给定一个英雄,英雄要打倒一个boss,英雄初始的血量与魔法值都是100,boss的血量也是100,输入n,t,p;分别表示英雄有n个技能,在每一轮双方攻击完后可以恢复t的魔法值,boss的攻击力为p。
后来n行每行两个数ai,bi(大于0小于100),表示使用技能需要的魔法值与技能的伤害(必须至少有ai的魔法值才能发动相对应的技能)。英雄也有一个普通攻击,不需要魔法值,伤害为1;
在每一回合中都是英雄先攻击。问最少用多少回合可以打倒boss,如在打倒boss之前英雄先死了就输出My god!
解法:因为每次boss的伤害是固定的,所以英雄死的时间也是固定的,所以如果在那个时间内不能杀死boss,就My god了。因为这题是师兄出的DP基础题,所以一开始就认定用DP做了,建立的数组dp[i][j]意思是在i轮boss剩下j血量的情况下英雄最大的魔法值为dp[j];(我一开始错误的想法是第i轮boss被扣了j血量的情况下英雄的最大魔法值dp[j],可惜错了,不知道为什么,求大神解答。。。)这思路是看其他大神博客得出的。
因为代码没有涉及到什么算法,主要是推出那个蛋疼的状态转移方程,所以就没有什么注释,也没有什么好说的。
网上面的DP讲座都说,最重要是搞清楚问题的决策与状态,这样才能写出状态转移方程。
所以小弟不才,就这题说说决策与状态(如果有错望各大神指出):
具体对照代码。。。
状态:boss剩下j血量的状态;
决策:是否使用第K个技能使状态变成:boss剩下j – skill[k].bi血量的状态。;(当然是在能使用这技能的情况下,前面有if判断)
而决策的判断条件就是魔法值了。因为在任何一个状态下,魔法值越多,就对英雄越有利。
所以态转移方程:dp[j – skill[k].bi] = max (dp[j – skill[k].bi],dp[j] – skill[k].ai + t);
#include <stdio.h>
#include <string.h>
typedef struct{
int ai;
int bi;
}node;
int max (int a,int b)
{
return a > b ? a : b ;
}
int main ()
{
node skill[110];
int n,t,q,i,j,k,p;
int dp[110];
while (scanf ("%d%d%d",&n,&t,&q))
{
p = 0;
if (n == 0 && t == 0 && q == 0)
break;
for (i = 1 ; i <= n ; i++)
scanf ("%d%d",&skill[i].ai,&skill[i].bi);
skill[0].ai = 0;
skill[0].bi = 1;
memset (dp,-1,sizeof(dp));
dp[100] = 100;
int time = (100 % q == 0) ? 100/q : 100 / q + 1 ;//英雄在time回合内要打到boss;
for (i = 1 ; i <= time ; i ++)
{
for (j = 1 ; j <= 100 ; j ++)
{
if (dp[j] == -1)
continue;
for (k = 0 ; k <= n ; k ++)
{
if (j <= skill[k].bi && dp[j] >= skill[k].ai)
{
printf ("%d\n",i);
p = 1;
break;
}
else if (j > skill[k].bi && dp[j] >= skill[k].ai)
{
dp[j - skill[k].bi] = max (dp[j - skill[k].bi],dp[j] - skill[k].ai + t);
if (dp[j + skill[k].bi] > 100)
dp[j + skill[k].bi] = 100;
}
}
if (p)
break;
}
if(p)
break;
}
if (!p)
printf ("My god\n");
}
}