zoukankan      html  css  js  c++  java
  • 2017百度之星资格赛 1003:度度熊与邪恶大魔王

    Problem:
    度度熊为了拯救可爱的公主,于是与邪恶大魔王战斗起来。 邪恶大魔王的麾下有n个怪兽,每个怪兽有a[i]的生命值,以及b[i]的防御力。 度度熊一共拥有m种攻击方式,第i种攻击方式,需要消耗k[i]的晶石,造成p[i]点伤害。 当然,如果度度熊使用第i个技能打在第j个怪兽上面的话,会使得第j个怪兽的生命值减少p[i]-b[j],当然如果伤害小于防御,那么攻击就不会奏效。 如果怪兽的生命值降为0或以下,那么怪兽就会被消灭。 当然每个技能都可以使用无限次。 请问度度熊最少携带多少晶石,就可以消灭所有的怪兽。

    Input:
    本题包含若干组测试数据。
    
    第一行两个整数n,m,表示有n个怪兽,m种技能。
    
    接下来n行,每行两个整数,a[i],b[i],分别表示怪兽的生命值和防御力。
    
    再接下来m行,每行两个整数k[i]和p[i],分别表示技能的消耗晶石数目和技能的伤害值。
    
    数据范围:
    
    1<=n<=100000
    
    1<=m<=1000
    
    1<=a[i]<=1000
    
    0<=b[i]<=10
    
    0<=k[i]<=100000
    
    0<=p[i]<=1000

    Output:
    对于每组测试数据,输出最小的晶石消耗数量,如果不能击败所有的怪兽,输出-1

    Sample Input
    1 2
    3 5
    7 10
    6 8
    1 2
    3 5
    10 7
    8 6

    Sample Out
    6
    18
    问题如上。
    关于这道题,网上大多采用的是完全背包求解,这里我用了另外一种方法——穷举。。。
    对于每个怪兽来说,所有的技能只有三种情况:
    1.技能攻击力 <= 怪兽防御力,此类技能无法对怪兽造成伤害,因此可以直接跳过;
    2.攻击力 >= 防御力 + 怪兽生命值,此类技能可以对怪兽一击秒杀,因此只需在此类技能中选择耗费晶石最少的技能即可;
    3.攻击力 > 防御力 && 攻击力 < 防御力 + 生命值,此类技能无法对怪兽一击秒杀,但可以造成伤害,因此需要多个技能组合起来杀死怪兽。
    这道题的难点在于第三种情况的技能该如何选择。
    首先,虽然每个技能可以无限次使用,但对于每个符合第三种情况的技能,当 使用次数 > 怪兽的生命值/(攻击力 - 防御力)+ 1 时,再使用此技能没有意义,因为之前的技能累加起来的伤害值已经足够把怪兽打死了。
    所以可以建立一个新数组,数组中储存符合第三种情况的技能,并且每个技能重复 生命值/(攻击力 - 防御力)+ 1 次,该数组的总长度也可以计算出来,这里先记为 length
    因此对于新数组中的每一项来说,就只有选和不选两种情况,如果用0代表不选,用1代表选,那么用 1~pow(2,length) - 1 这之间数字的二进制形式就可以表示出来所有情况。
    对于每一种情况,即每个数字的二进制形式,只需找出含1的位置,因为二进制形式的每个位置都与此前建立的新数组对应,因此就可以得到当前情况的技能选择,从而可以求出这种情况造成的伤害值和耗费的晶石数量。
    若当前伤害值不超过怪兽的生命值,则可以跳过这次情况;
    若当前耗费晶石数量大于一开始的第二种情况(攻击力 >= 防御力 + 生命值),也可以跳过这次情况。所以只需在剩下的情况中选择耗费晶石数量最少的情况即可。


    以下是具体实现代码
     1 #define min(a, b) (a) < (b) ? (a) : (b)
     2 
     3 class Solution
     4 {
     5 public:
     6     int dudubear(vector<int> life, vector<int> defense, vector<int> star, vector<int> attack, int n, int m)
     7     {
     8         int rightMinValue = 100000, leftMinValue = 100000, sum = 0;
     9         vector<int> selectValue;
    10         vector<int> newselectValue;
    11 
    12         for (int i = 0; i < n; ++i)
    13         {
    14             for (int j = 0; j < m; ++j)
    15             {
    16                 if (attack[j] >= life[i] + defense[i])
    17                 {
    18                     rightMinValue = min(star[j], rightMinValue);
    19                     continue;
    20                 }
    21                 if ((attack[j] > defense[i]) && (attack[j] < defense[i] + life[i]))
    22                 {
    23                     selectValue.push_back(j);
    24                     continue;
    25                 }
    26                 if (j == m - 1)
    27                 {
    28                     return -1;
    29                 }
    30             }
    31             //因为技能可重复使用,但单个技能重复使用累加起来的伤害(攻击-防御)超过怪兽的生命值时无意义
    32             //所以每个技能的使用次数不能超过(life[i] / (attack[selectValue[j]] - defense[i]))+1
    33             //建立新数组,储存单个技能使用最大次数的数组
    34             int count = 0;
    35             for (int j = 0; j < selectValue.size(); ++j)
    36             {
    37                 int items = (life[i] / (attack[selectValue[j]] - defense[i])) + 1;
    38                 for (int k = 0; k < items; ++k)
    39                 {
    40                     newselectValue.push_back(selectValue[j]);
    41                     ++count;
    42                 }
    43             }
    44 
    45 
    46             int flag = 4;
    47             int bitcount = 2;
    48             for (int j = 3; j < (int)pow(2, count); ++j)
    49             {
    50                 if (j == flag)
    51                 {
    52                     flag = flag << 1;
    53                     ++bitcount;
    54                     continue;
    55                 }
    56                 //计算当前情况所耗费晶石数量
    57                 int sumDamage = 0, sumStar = 0;
    58                 for (int k = 1; k < bitcount + 1; ++k)
    59                 {
    60                     if ((j >> (k - 1) & 1) == 1)
    61                     {
    62                         sumDamage += attack[newselectValue[count - k]] - defense[i];
    63                         sumStar += star[newselectValue[count - k]];
    64                     }
    65                 }
    66                 if (sumDamage < life[i])
    67                     continue;
    68                 if (sumStar > rightMinValue)
    69                     continue;
    70                 leftMinValue = min(sumStar, leftMinValue);
    71             }
    72             leftMinValue == 100000 ? sum += rightMinValue : sum += leftMinValue;
    73             leftMinValue = 100000;
    74             rightMinValue = 100000;
    75             selectValue.clear();
    76             newselectValue.clear();
    77         }
    78 
    79         return sum;
    80     }
    81 };
  • 相关阅读:
    javascript 去掉 url 中的不可打印字符串
    双链表 哈希 go 实现lFU 缓存算法
    博客园嵌入背景音乐
    博客园嵌入B站视频教程
    基于C++二叉树链表实现同学录信息系统
    C++ 二叉树知识点
    datatable 自定义排序 及 多列排序
    jq 提取字符串中的数字
    wamp下thinkPHP3.2 系统不支持:redis 解决方法
    editable文档
  • 原文地址:https://www.cnblogs.com/yeqingqian/p/7668377.html
Copyright © 2011-2022 走看看