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 };
  • 相关阅读:
    PAT A1094 The Largest Generation (25 分)——树的bfs遍历
    PAT A1055 The World's Richest (25 分)——排序
    PAT A1052 Linked List Sorting (25 分)——链表,排序
    PAT A1076 Forwards on Weibo (30 分)——图的bfs
    辅导员
    辅导员面试
    C程序设计
    Excel VBA 基本概念
    Excel函数
    导入excel表的数据到数据库ssh
  • 原文地址:https://www.cnblogs.com/yeqingqian/p/7668377.html
Copyright © 2011-2022 走看看