• 2002-2003 ACM-ICPC Northeastern European Regional Contest (NEERC 02) H Heroes Of Might And Magic (隐含dp)


    问题是求一个方案,实际隐含一个dp。法力是递减的,所以状态是DAG,对于一个确定的状态,我们贪心地希望英雄的血量尽量大。

    分析:定义状态dp[i][p][h]表示是已经用了i的法力值,怪兽的位置在p,怪兽的总血量为h时候英雄所具有的最大血量,

    采用刷表法,决策有:

    使用雷击,h变成h-L[p],p变成max(p-V,1),如果怪兽移动结束以后在1号位置且没有击杀怪物h-L[p]>0(注意这种情况),

    会对英雄造成ceil((h-L[p])/HPm)点伤害,如果dp[i][p][h]-damge<=0,那么转移是非法的。

    使用传送,传送到1是没有意义的,从2开始枚举,假设传送的位置为tp,那么怪物的下一个位置会是max(tp-V,1),处理一下伤害和转移即可。

    使用治疗,注意判断一下血量上限。

    具体处理的时候,记录一个pre状态数组和相应操作,用一个vis数组表示下一个阶段的状态是否出现过。

    习惯用滚动数组,直接写反而觉得别扭。。。

    转移麻烦的写个updata效果拔群

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 11;
    int N,HPh,MPh,HPm,Nm,V,dH;
    int L[maxn];
    
    
    #define MP make_pair
    typedef pair<int,int> Node;
    #define fi first
    #define se second
    #define PB push_back
    
    const int maxh = 1001;
    int dp[2][maxn][maxh];
    bool vis[maxn][maxh];
    char opt[50][maxn][maxh];
    Node pre[50][maxn][maxh];
    int optp[50][maxn][maxh];
    
    
    
    void print_ans(int i,Node rt)
    {
        printf("VICTORIOUS
    ");
        stack<Node> S; S.push(rt);
        while(i>0){
            Node &u = S.top();
            S.push(pre[i][u.first][u.second]); i--;
        }
        while(S.size()){
            Node &u = S.top();
            char ch = opt[i][u.fi][u.se];
            putchar(ch);
            if(ch == 'T') printf(" %d",optp[i][u.first][u.second]);
            putchar('
    ');
            S.pop();
            i++;
        }
    }
    
    void updata(int i,int nps,int Hm,char op,int opp,Node &u,int val,int (*nex)[maxh])
    {
        opt[i][nps][Hm] = op;//操作指令
        optp[i][nps][Hm] = opp;//传送相关
        pre[i][nps][Hm] = u;//前驱状态
        nex[nps][Hm] = val;//更新val值
    }
    
    
    void solve()
    {
        vector<Node> V1,V2,*q1 = &V1,*q2 = &V2;
        q1->PB({N,Nm*HPm}); dp[0][N][Nm*HPm] = HPh;
        for(int i = 0; i < MPh; i++){
            memset(vis,0,sizeof(vis));
            int (*d1)[maxh] = dp[i&1], (*d2)[maxh] = dp[(i&1)^1];//当前状态,和上一层状态
            for(int j = 0; j < (int)q1->size(); j++){
                Node &u = q1->at(j);
                //雷击
                int nps = max(u.fi-V,1);//怪兽移动后的位置 next_pos
                int tHp = max(u.se-L[u.fi],0);//攻击后怪兽的HP
                int val = d1[u.fi][u.se];//英雄血量
                int damege = 0;
                if(nps == 1){ damege = (tHp+HPm-1)/HPm;}//怪兽移动后到达1号格子,对英雄攻击
                if(val-damege>0 || tHp == 0){//英雄能承受攻击 或者 怪物已经死了
                    if(!vis[nps][tHp]){//状态判重
                        vis[nps][tHp] = true, q2->PB({nps,tHp});
                        updata(i,nps,tHp,'L',-1,u,val-damege,d2);
                        if(tHp == 0) {
                            print_ans(i,Node(nps,0)); return;
                        }
    
                    }else if(d2[nps][tHp] < val-damege){
                        updata(i,nps,tHp,'L',-1,u,val-damege,d2);
                        if(tHp == 0) {
                            print_ans(i,Node(nps,0)); return;
                        }
                    }
                }
                //传送
                for(int tp = 2; tp <= N; tp++){//传送到tp位置
                    int tnps = max(tp-V,1);//怪物移动
    
                    int tval = d1[u.first][u.second];
                    if(tnps == 1){
                        tval -= (u.se+HPm-1)/HPm;
                    }
                    if(tval>0){
                        if(!vis[tnps][u.second]){
                            vis[tnps][u.se] = true,q2->PB({tnps,u.se});
                            updata(i,tnps,u.se,'T',tp,u,tval,d2);
                        }else if(d2[tnps][u.second] < tval){
                            updata(i,tnps,u.se,'T',tp,u,tval,d2);
                        }
                    }
    
                }
    
                if(nps == 1){ damege = (u.se+HPm-1)/HPm;}//未使用雷击时怪兽造成的伤害
                else damege = 0;
                val = min(d1[u.fi][u.se]+dH,HPh);//治疗
                if(val>damege){
                    val -= damege;
                    if(!vis[nps][u.se]){
                        vis[nps][u.se] = true; q2->PB({nps,u.se});
                        updata(i,nps,u.se,'H',-1,u,val,d2);
                    }else if(d2[nps][u.se] < val){
                        updata(i,nps,u.se,'H',-1,u,val,d2);
                    }
                }
    
            }
            q1->clear();
            swap(q1,q2);
        }
        puts("DEFEATED");
    }
    
    int main()
    {
        freopen("heroes.in","r",stdin);
        freopen("heroes.out","w",stdout);
        cin>>N>>HPh>>MPh>>HPm>>Nm>>V>>dH;
        for(int i = 1; i <= N; i++) scanf("%d",L+i);
        solve();
        return 0;
    }
  • 相关阅读:
    [spoj DISUBSTR]后缀数组统计不同子串个数
    [poj 3261]后缀数组+滑窗最小值
    [poj 1743]差分+后缀数组
    [codechef MEXDIV]Mex division
    JavaScript中的数组和对象 增删遍
    ajax返回的值有两种方法,一种是把async:true改为false。 另一种是回调函数。
    使用smart-npm和npm安装完毕之后发现 不是内部命令和外部命令!
    移动端rem设置,自动更改html<font-size>
    总结js创建object的方式(对象)
    用css方法 可以实现多行 超出宽度 出点点点号
  • 原文地址:https://www.cnblogs.com/jerryRey/p/4782550.html
Copyright © 2020-2023  润新知