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\n");
    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('\n');
        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;
}

 

posted @ 2015-09-04 23:03  陈瑞宇  阅读(259)  评论(0编辑  收藏  举报