BZOJ 3709 [PA2014]Bohater:贪心【反过来考虑】

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3709

题意:

  在一款电脑游戏中,你需要打败n只怪物(从1到n编号)。

  为了打败第i只怪物,你需要消耗atk[i]点生命值,但怪物死后会掉落血药,使你恢复rec[i]点生命值。

  任何时候你的生命值都不能降到0(或0以下)。

  请问是否存在一种打怪顺序,使得你可以打完这n只怪物而不死掉。

 

题解:

  怪物总共分两种,一种是打完能回血的,一种是打完会掉血的。

  显然,先打能回血的,再打能掉血的。

  分别考虑两种怪:

    (1)能回血的:

      显然,先打atk小的怪物。按atk升序排列。

    (2)会掉血的:

      最后打完所有怪之后的血量end是一定的。

      那么将这个过程反过来考虑:初始血量为end,每打一个怪物掉rec[i]的血,然后回atk[i]的血。

      所以按照rec降序排列。

  最后模拟一遍能不能打完就行了。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <algorithm>
 5 #define MAX_N 100005
 6 
 7 using namespace std;
 8 
 9 struct Mons
10 {
11     int atk;
12     int rec;
13     int idx;
14     Mons(int _atk,int _rec,int _idx)
15     {
16         atk=_atk;
17         rec=_rec;
18         idx=_idx;
19     }
20     Mons(){}
21     friend bool operator < (const Mons &a,const Mons &b)
22     {
23         if(a.rec-a.atk>=0 && b.rec-b.atk>=0) return a.atk<b.atk;
24         else if(a.rec-a.atk<0 && b.rec-b.atk<0)return a.rec>b.rec;
25         return a.rec-a.atk>b.rec-b.atk;
26     }
27 };
28 
29 int n;
30 long long hp;
31 bool failed=false;
32 Mons mons[MAX_N];
33 
34 void read()
35 {
36     cin>>n>>hp;
37     for(int i=1;i<=n;i++)
38     {
39         cin>>mons[i].atk>>mons[i].rec;
40         mons[i].idx=i;
41     }
42 }
43 
44 void solve()
45 {
46     sort(mons+1,mons+n+1);
47     for(int i=1;i<=n;i++)
48     {
49         hp-=mons[i].atk;
50         if(hp<=0)
51         {
52             failed=true;
53             break;
54         }
55         hp+=mons[i].rec;
56     }
57 }
58 
59 void print()
60 {
61     if(failed)
62     {
63         cout<<"NIE"<<endl;
64         return;
65     }
66     cout<<"TAK"<<endl;
67     for(int i=1;i<=n;i++)
68     {
69         cout<<mons[i].idx<<" ";
70     }
71     cout<<endl;
72 }
73 
74 int main()
75 {
76     read();
77     solve();
78     print();
79 }

 

posted @ 2017-10-10 21:49  Leohh  阅读(155)  评论(0编辑  收藏  举报