状态压缩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 }

  以后看着复习就省事多了

转载于:https://www.cnblogs.com/Chinahenu/p/3910583.html

标题基于Python的自主学习系统后端设计与实现AI更换标题第1章引言介绍自主学习系统的研究背景、意义、现状以及本文的研究方法和创新点。1.1研究背景与意义阐述自主学习系统在教育技术领域的重要性和应用价值。1.2国内外研究现状分析国内外在自主学习系统后端技术方面的研究进展。1.3研究方法与创新点概述本文采用Python技术栈的设计方法和系统创新点。第2章相关理论与技术总结自主学习系统后端开发的相关理论和技术基础。2.1自主学习系统理论阐述自主学习系统的定义、特征和理论基础。2.2Python后端技术栈介绍DjangoFlask等Python后端框架及其适用场景。2.3数据库技术讨论关系型和非关系型数据库在系统中的应用方案。第3章系统设计与实现详细介绍自主学习系统后端的设计方案和实现过程。3.1系统架构设计提出基于微服务的系统架构设计方案。3.2核心模块设计详细说明用户管理、学习资源管理、进度跟踪等核心模块设计。3.3关键技术实现阐述个性化推荐算法、学习行为分析等关键技术的实现。第4章系统测试与评估对系统进行功能测试和性能评估。4.1测试环境与方法介绍测试环境配置和采用的测试方法。4.2功能测试结果展示各功能模块的测试结果和问题修复情况。4.3性能评估分析分析系统在高并发等场景下的性能表现。第5章结论与展望总结研究成果并提出未来改进方向。5.1研究结论概括系统设计的主要成果和技术创新。5.2未来展望指出系统局限性并提出后续优化方向。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值