状态压缩DP----HDU2809

    状态压缩DP的一道较不错的入门题,第二次做这类问题,感觉不是很顺手,故记录下来.

    题目的意思就是吕布战群雄,先给你6个数,分别是吕布的攻击值,防御值,生命值,升级后此三值各自的增量,然后是对手的个数num,接下来是各个对手的名字,攻击值,防御值,生命值,及经验值,规定当吕布经验值每提升100,则攻击值,防御值,生命值加上各自的增量。最后若生命值大于0,输出生命值,否则输出一句话"Poor LvBu,his period was gone."。

刚开始看到此题实在看不出是用压缩DP,以为是普通的DP。但只细一想,状态数太多了并且和编号有关联,原因是:假设与吕布对战的人有三个分别是关羽,张飞,许褚,则现在问题出来了。吕布按什么顺序来对战此三人,吕布-->关羽-->张飞-->许褚,吕布-->张飞-->关羽-->许褚等等,以及战胜一人后生命值是否为零,两人呢.......?这样想着发现很乱很乱,状态多并且不好表示(这不二进制中1正好是状态压缩擅长的嘛)。于是定义状态表达式LvBu[i],i对应的二进制中1代表已和此人对战,如5=101表示分别和关羽,许褚fight了,就差张飞了。但麻烦又来了,101是先和关羽打呢,还是先和许褚打,这里要特别注意的是和谁先打的顺序可能会导致结果不同,例如我先打关羽得到的经验值少不能升级,而我先打许褚升级的经验值就足够了,很明显这两个结果的生命值肯定不会相同。那么怎么解决呢?这只要在for循环时进行更新就可以了

接下来详细解释代码,

 1 #include <iostream>
 2 #include <cstdio>
 3 
 4 using namespace std;
 5 
 6 struct Person{
 7 int attck;
 8 int defense;
 9 int hp;
10 int expirence;
11 }LvBu[1<<21],Enemy[21],Update;//定义结构体,并分配相应的数组,对手最多20个
12 int result,num;
13 
14 inline int max(int a,int b) //最大值函数
15 {
16     if(a>b) return a;
17     return b;
18 }
19 
20 void Fight()
21 {
22     int attck,defence;
23     int myTime,Time;
24     int rHp,expirence,rattack,rdef;
25     for(int i=0;i<=result;i++)//状态
26         for(int j=0;j<num;j++)//对手编号从0到num-1
27         {
28             if(!(i&(1<<j))&&LvBu[i].hp>0)//若吕布未与编号j对手交战并且生命值不为零,有对战的必要
29             {
30                 attck=max(1,LvBu[i].attck-Enemy[j].defense);//依题目条件吕布攻击一次对方掉attck点血
31                 defence=max(1,Enemy[j].attck-LvBu[i].defense);//对方攻击一次吕布掉defence点血
32                 myTime=(LvBu[i].hp+defence-1)/defence;//吕布可以攻击的总次数
33                 Time=(Enemy[j].hp+attck-1)/attck;//对手可以攻击的总次数
34           //如关羽生命值是8,吕布攻击一次造成伤害为-3,那么吕布总共可以攻击3次,那么用一行代码如何表示呢?可以先拿1单位的血出来,剩下的直接除以伤害值
35                 if(myTime<Time) continue;//吕布先挂了,否则继续执行
36                 rHp=(LvBu[i].hp-(Time-1)*defence);//剩余生命值原本的减去代价值,Time减一的原因是对手先倒下了,原本你打我一下,我打你一下成偶数的,你走的早就打不到我了
37                 expirence=Enemy[j].expirence+LvBu[i].expirence;//得到经验值
38                 rattack=LvBu[i].attck;rdef=LvBu[i].defense;//之所以这样是方便后面书写
39 
40                 if(expirence>=100)//可以升级
41                 {
42                     expirence-=100;//付出100点经验值为代价
43                     rattack+=Update.attck;
44                     rdef+=Update.defense;
45                     rHp+=Update.hp;
46                 }
47 
48                 if(rHp>=LvBu[i|(1<<j)].hp)//这就是我先打许褚-->关羽,还是关羽-->许褚的更新了
49                 {
50                     LvBu[i|(1<<j)].attck=rattack;
51                     LvBu[i|(1<<j)].defense=rdef;
52                     LvBu[i|(1<<j)].hp=rHp;
53                     LvBu[i|(1<<j)].expirence=expirence;
54                 }
55             }
56         }
57     if( LvBu[result].hp) printf("%d\n",LvBu[result].hp);
58     else printf("Poor LvBu,his period was gone.\n");
59 }
60 int main()
61 {
62     while(scanf("%d %d %d %d %d %d",&LvBu[0].attck,&LvBu[0].defense,&LvBu[0].hp,&Update.attck,&Update.defense,&Update.hp)!=EOF)
63     {   //输入
64         LvBu[0].expirence=0;//吕布初始经验值为0
65         char name[21];
66         scanf("%d",&num);
67         for(int i=0;i<num;i++)
68         scanf("%s%d%d%d%d",name,&Enemy[i].attck,&Enemy[i].defense,&Enemy[i].hp,&Enemy[i].expirence);
69         result=(1<<num)-1;//状态总数
70 
71         for(int i=1;i<=result;i++) LvBu[i].hp=0;//初始化
72         Fight();//对战
73     }
74     return 0;
75 }

  以后看着复习就省事多了

posted on 2014-08-13 17:04  沐曦枫,梦莲  阅读(570)  评论(0编辑  收藏  举报

导航