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 }