• HDU 2809 God of War(DP + 状态压缩)


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2809

    题目大意:给出战神吕布的初始攻击力ATI、防御力DEF、生命值HP、每升一级增加的攻击力In_ATI,增加的防御力In_DEF和增加的生命值In_HP。然后给出n个敌人的攻击力、防御力、生命值和杀死该单位能获得的经验值EXP。  吕布的初始经验值EXP是0,初始等级level是1,每当EXP>=level*100时就会升级。

      在吕布LvBu和敌人A之间的战斗有3条规则

      1.吕布攻击A,A失去 Max(1,LvBu's ATI- A's DEF) HP;

      2.A攻击吕布,吕布失去Max(1,A'ATI- LvBu'DEF)HP;

      3.战斗持续到任意一方死亡

    如果吕布能够将全部敌人杀死,并且自己不死,那么输出能够余下的最大HP,否则输出"Poor LvBu,his period was gone."

    Sample Input
    100 80 100 5 5 5
    2
    ZhangFei 95 75 100 100
    XuChu 90 90 100 90
    100 75 100 5 5 5
    1
    GuanYu 95 85 100 100
     
    Sample Output
    30
    Poor LvBu,his period was gone.

    分析:

    由于涉及到最优结果 以及 单挑顺序对结果带来的影响,使用状态压缩dp来解这道题。

    想讲一下思路,比如现在吕布跟三个人战斗,用1表示已经战胜这个人, 0表示没有。那个所有的情况(在不考虑顺序的情况下)就有2的3次方,8种可能,包括000。用对应的十进制表示。如图

    hdu <wbr>2809 <wbr>God <wbr>of <wbr>War

      可见,3的状态可以由1,2来求,5可以用1,4来求,6可以用2, 4来求,7可以用3, 5, 6状态来求,这就有了一个状态转移的方程在里面了。

    有些同学就想问那顺序怎么办呢。

      我们要计算3的最优状态的时候,会由1,跟2,来推出

      1状态表示打败第一个人

      2状态只表示第二个人

      那么3状态由1状态来计算的时候,就是先打第一个人再打第二个人

      而3状态由2状态来计算的时候,就是先打第二个人再打第一个人, 计算后的结果与当前的3状态的结果比较,把最优的覆盖上去就可以了。

      这个过程是不是有了一个顺序在里面了呢。

     

      而在代码里面,我们是由底向上计算额。比如历遍到第1个状态点的。我们可以计算上面的第3个点,跟第5个状态点,寻找的过程由位运算来实现。

    代码如下:

     1 # include<stdio.h>
     2 # include<string.h>
     3 int max(int a,int b){
     4     return a>b ?a :b;
     5 }
     6 struct Lvbu{
     7     int ATI,DEF,HP,EXP,level;
     8 }lv,dp[1<<20];    //dp[i]表示在在集合i下,吕布能达到的最好状态
     9 
    10 struct Enemy{
    11     char name[25];
    12     int ATI,DEF,HP,EXP;    
    13 }en[20];
    14 
    15 int In_ATI,In_DEF,In_HP,n;
    16 
    17 int main(){
    18     int i,j;
    19     while(scanf("%d%d%d%d%d%d",&lv.ATI,&lv.DEF,&lv.HP,&In_ATI,&In_DEF,&In_HP) != EOF){
    20         lv.EXP = 0;        //吕布初始经验为0,初始等级为1
    21         lv.level = 1;
    22         scanf("%d",&n);
    23         for(i=0;i<n;i++)
    24             scanf("%s%d%d%d%d",en[i].name,&en[i].ATI,&en[i].DEF,&en[i].HP,&en[i].EXP);
    25         int s,recent;
    26         int endstate = 1<<n;
    27         dp[0] = lv;    //dp[0]表示集合0,即没有攻击任何一个敌人时,吕布的状态,初始化
    28         bool flag;
    29         
    30         for(s=1; s<endstate; s++){
    31             flag = false;    //判断是否可以打败敌人
    32             for(i=0; i<n; i++){
    33                 recent = 1<<i;        
    34                 if(s & recent){        //如果在该集合里边,吕布打败了第i个敌人
    35                     Lvbu tmp=dp[s^recent];        //取出吕布没有打败第i个人,但是打败了状态s里边的其他所有人
    36                     if(tmp.level < 1)    continue;    //已经死亡
    37                     int dec = tmp.ATI - en[i].DEF;    //吕布的攻击力
    38                     if(dec <= 0) dec = 1;        //特殊情况
    39                     
    40                     int times = en[i].HP / dec;        //吕布杀死敌人的时间
    41                     if(times * dec != en[i].HP) times++;
    42                     
    43                     dec = en[i].ATI - tmp.DEF;    //敌人的攻击力
    44                     if(dec <= 0) dec = 1;
    45                     tmp.HP -= dec*(times - 1);    //吕布受到的伤害
    46                     
    47                     if(tmp.HP <= 0)        continue;    //如果死亡,跳出
    48                     
    49                     tmp.EXP += en[i].EXP;    //获得该角色经验
    50                     if(tmp.EXP >= tmp.level* 100){    //如果经验足够升级
    51                         int add = tmp.EXP/100 - tmp.level + 1;        //可升多少级
    52                         tmp.level += add;        //各项技能强化
    53                         tmp.ATI += add*In_ATI;
    54                         tmp.DEF += add*In_DEF;
    55                         tmp.HP += add*In_HP;
    56                     }
    57                     if(!flag || (tmp.HP>dp[s].HP) ||tmp.level>dp[s].level){        //选取最优的方案,并且置flag为真
    58                         dp[s] = tmp;
    59                         flag = true;
    60                     }
    61                 }
    62             }        
    63             if(!flag) dp[s].level = -1;    //如果不能打败该集合里的敌人,那么令等级为-1
    64         }
    65         
    66         lv = dp[endstate -1];    //将所有敌人打倒的状态 (1<<n)-1
    67         if(lv.level < 1) 
    68             printf("Poor LvBu,his period was gone.
    ");
    69         else
    70             printf("%d
    ",lv.HP);
    71     }
    72     return 0;
    73 }
  • 相关阅读:
    顶尖操盘手买入规则
    一个网友在评论见义勇为时候应该注意事项
    20111215 白糖空头控盘下的多头陷阱(与魂灵共舞)
    近期au黄金市场的探讨(2011年12月27日)
    ASP.NET MVC 中,手动移除已注册到容器的规则方法
    VS2010功能——任务列表
    关于SQL排序,父条件对应子条件排序
    确保每一步的业务代码都能够正确执行。
    C#程序代码中常用的快捷键
    cmd 下创建新文件(不是文件夹)
  • 原文地址:https://www.cnblogs.com/acm-bingzi/p/3292512.html
Copyright © 2020-2023  润新知