ZOJ 3446 Doraemon's Battle (三维dp+BFS)【打怪类模板】

Doraemon is fighting with n enemies.

Doraemon has two properties in this battle, HP and SPHP is the health point of Doraemon with initial value lh. If Doraemon's HP decreased to 0 or lower, Doraemon will lose the battle. SP is a property for using Doraemon's skill with initial value 0, which will be described later. HP has an upper bound lh (its initial value) and SP has an upper bound ls.

Doraemon and his enemies take turns to act. Doraemon acts before his enemies in each turn.

In each turn Doraemon can choose one of the following actions:

  • Kill one enemy and get his SP increased by 1.
  • Heal himself. Doraemon's HP will increase by floor(0.2*lh).
  • Use his skill if SP > 0. His skill will kill D[SP] enemies and reset his SP to 0. D is a sequence of integer which will be described in the input.
  • Do nothing.

Enemies will attack after Doraemon's action. Each enemy will cause one point damage to Doraemon. In the end of each turn, Doraemon get his SP increased by e mod 3 where e is the number of remaining enemies.

Now Doraemon wants to know the minimum number of turns he can kill all enemies.

Input

Input contains multiple cases, process to the end of input.

Each case contains two lines. The first line has three integers, lh (1 ≤ lh ≤ 250), ls (1 ≤ ls ≤ 100) and n. (1 ≤ n ≤ 40)

The following line describes sequence D mentioned in Doraemon's skill. The line contains ls integers, the ith integer refers to D[i] (1 ≤ D[i] ≤ 10).

Output

For each case, output the minimum number of turns needed in a single line. If Doraemon will always lose the battle, print "HELP!" instead.

Sample Input
5 2 4
2 3
Sample Output
3

 【题解】

 很经典的一道dp题,虽说是dp,但是我觉得更像是BFS题,这道题题意很难懂,不停的揣摩条件,而且限制极多,稍有不注意就会丢掉一个条件,这道题不知道哇了多少遍,终于A了,下面来说一下。

 题意输入:最大hp,最大sp,敌人数; 然后第二行是第i个值代表i点sp值可以杀死a[i]只怪兽。


    首先,这个题有很多模糊的坑点。

  1、每回合都是哆啦A梦先攻击,然后怪兽再攻击哆啦A梦。

  2、不论是普攻杀死还是技能杀死怪兽,都会回复怪兽数%3的sp值。

  3、每个技能可以无限用。

  4、sp初始值为0!!!这儿特别坑。

  5、原地回复hp的时候怪兽也会攻击他。


 然后重点来了,过程模拟:每回合有三种状态,一、杀死一只怪兽并且回复1点sp值;二、原地回复一定量的hp值;

 三、如果sp值大于0,用技能杀死一定数量的怪兽,同时sp值清零,然后回复剩余怪兽数%3的sp值;

 所以每回合可以模拟这三种状态,如果第j中状态下怪物数量小于等于0,或者所剩sp值能杀死的怪物数量大于剩余怪物数量,就直接返回当前回合数,否则就把剩余状态加入到队列中,一直搜,如果搜到结尾也没结果,就返回-2,表示需要help。更详细的步奏见代码注释:


【AC代码】

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int m,n;
int up_sp,up_hp;
int a[300];//其实开105就够了
int add_hp;
int dp[255][105][45]; //第一维-hp,第二维-sp,第三维-敌人数量n;

struct dro
{
    int hp,sp;
    int num;
    void init(int lh,int ls,int x)
    {
        if(lh>up_hp) lh=up_hp;//hp不超上限
        if(ls>up_sp) ls=up_sp;//sp不超上限
        hp=lh;sp=ls; num=x;
    }
}ss;

void Init() //初始化
{
    for(int i=0;i<255;++i)
        for(int j=0;j<105;++j)
            for(int k=0;k<45;++k)
               dp[i][j][k]=0;
}

int bfs()
{
    queue<dro> q;
    while(!q.empty()) q.pop();
    q.push(ss);
    dp[ss.hp][ss.sp][ss.num]=1;//第一回合
    dro st,ed;
    while(!q.empty())
    {
        st=q.front();
        q.pop();
        ed.init(st.hp-(st.num-1),st.sp+1+(st.num-1)%3,st.num-1);//第一种状态:杀死一个敌人,剩余怪兽攻击自己,sp值回复1点再加上敌人数%3的sp值
        if(ed.num<=0) return dp[st.hp][st.sp][st.num];//敌人杀没了
        if(ed.hp>0 && !dp[ed.hp][ed.sp][ed.num])//自己还活着并且当前状态没遇到过
        {
            dp[ed.hp][ed.sp][ed.num]=dp[st.hp][st.sp][st.num]+1;//回合加1
            q.push(ed);
        }
        ed.init(st.hp+add_hp-st.num,st.sp+st.num%3,st.num);//原地回血,同时减去怪物造成的攻击值,回复sp值,敌人数量不变
        if(ed.hp>0 && !dp[ed.hp][ed.sp][ed.num])//还活着
        {
            dp[ed.hp][ed.sp][ed.num]=dp[st.hp][st.sp][st.num]+1;//回合数加1
            q.push(ed);
        }
        if(st.sp>0)
        {
            if(st.num<=a[st.sp])//当前技能值可以一次杀完所有敌人就直接返回当前回合数
            {
                return dp[st.hp][st.sp][st.num];
            }
            ed.init(st.hp-(st.num-a[st.sp]),(st.num-a[st.sp])%3,st.num-a[st.sp]);//用技能杀死a[st.sp]个敌人,同时受到伤害,回复sp;
            if(ed.hp>0 && !dp[ed.hp][ed.sp][ed.num])//被围攻但还活着
            {
                dp[ed.hp][ed.sp][ed.num]=dp[st.hp][st.sp][st.num]+1;//回合数加1
                q.push(ed);
            }
        }
    }
    return -2; //没找到能杀完怪兽的策略就返回-2
}

int main()
{
    while(~scanf("%d%d%d",&up_hp,&up_sp,&n))
    {
        for(int i=1;i<=up_sp;++i)
           scanf("%d",&a[i]);
        Init();
        add_hp=(int)(up_hp*0.2); //转整型
        ss.init(up_hp,0,n);//初始hp为最大值,sp为0,!!!,敌人数为n
        int ans=bfs();
        if(ans==-2)//没找到状态
            printf("HELP!\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值