暑期dp46道(27)--HDOJ 3008 Warcraft

题目链接: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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值