题目链接:HDOJ 3008
题意:如果我没看错,应该是魔兽吧,表示没玩过嘿嘿,意思就是初始满的魔法值,己方和魔兽生命值都是100,每秒 钟对魔兽可以采取普攻(平A)造成1点伤害,也可以使用当前魔法值可以释放的任一技能,造成技能伤害,每 次攻击过后可以恢复最多t的魔法值,但是上限为100,魔兽每秒对你造成固定伤害,你首先发起进攻,求最终谁 会先game over,若是你胜利输出最小的时间,若是魔兽胜,输出"My god";
题解:这个和之前员工雇佣相似,但是区别在员工那题dp子问题的每个状态都会存在,但是这个不一定,因为魔法值是“跳”着变化的,所以要判断子问题的状态是否存在,可以初始化标记。
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
#define debug 0
#define M(a, b) memset(a, b, sizeof(a))
#define Max(a,b) ( (a > b ) ? a : b)
#define Min(a,b) ( (a < b ) ? a : b)
#define INT 1 << 29
#define REP(o) for(int i = 1; i <= o; i++)
const int maxn = 100 + 5;
int n,t,q,c[maxn],w[maxn],total,dp[maxn][maxn];
void Do()
{
for(int i = 1; i <= total; i++)
{
for(int j = 0; j <=100 ; j++)//枚举可能魔法值
{
if(dp[i - 1][j] != -1)//如果上一秒这个状态存在,dp
{
for(int k = 1; k <= n; k++)
{
if(j - c[k] >= 0)//使用第k种魔法
{
int temp = (j - c[k] + t > 100) ? 100 : j - c[k] + t;//上限
if(dp[i][temp] ==-1)//如果当前第i秒这个状态不存在,直接更新
{
dp[i][temp] = dp[i-1][j]+w[k];
}
else
{
dp[i][temp] = Max(dp[i][temp], dp[i - 1][j] + w[k]);//存在找最大值
}
if(dp[i][temp] >= 100)//魔兽over,输出结果return,因为是最优解,所以肯定是最小值
{
printf("%d\n",i);
return;
}
}
}
int temp = (j + t > 100) ? 100 : j + t;//平A
if(dp[i][temp] == -1)
dp[i][temp] = dp[i - 1][j] + 1;
else
dp[i][temp] = Max(dp[i][temp], dp[i - 1][j] + 1);
if(dp[i][temp] >= 100)
{
printf("%d\n",i);
return;
}
}
}
}
printf("My god\n");
}
int main()
{
#if debug
freopen("in.txt","r",stdin);
#endif//debug
while(~scanf("%d%d%d",&n,&t,&q))
{
if(n == 0 && t == 0 && q == 0)
break;
REP(n)
scanf("%d%d",&c[i],&w[i]);
total = (100 % q == 0) ? 100 / q : 100 /q + 1;//己方的最大时间,
M(dp, -1); //因为先手,所以若不是整除可+1,初始化标记状态
dp[0][100] = 0;//0秒时满魔伤害为0
Do();
}
return 0;
}