【贪心算法】19270:勇士斗恶龙
题目描述
小 X 穿越到了异世界,国王命令他招揽勇士,杀死恶龙,救回公主。
异世界是高度数据化的。恶龙有一个攻击力 ATK,一个生命值 HP。类似的,每个勇士也有一个攻击力 Ai,一个生命值 Hi。
战斗是回合制的,并且每次只能由一个勇士和恶龙单挑。战斗中,每个回合恶龙的生命值会减去这个勇士的攻击力,这个勇士的生命值会减去恶龙的攻击力。
如果回合结束的时候恶龙的生命值小于等于 0,那么恶龙就被杀死了;如果这个勇士的生命值小于等于 0,那么这个勇士就被击败了,需要换上另一个勇士继续战斗。当然,如果恶龙还没有被杀死,勇士却全部被击败了,那么这场战役就彻底失败了。
不过聪明的小 X 安排了一个特殊的战术:在一名勇士被击败后立刻让另一名勇士发起攻击,这样恶龙在勇士们的车轮战术下疲于招架,受到第二个勇士的伤害变为两倍,受到第三个勇士的伤害变为三倍……以此类推。
现在一共有 n 名勇士报名,小 X 想问问你,如果合理安排勇士出战的顺序,最少要招揽多少名勇士才能杀死恶龙?
输入
第一行为一个正整数 n,表示一共有 n 名勇士报名。
第二行两个正整数 ATK 和 HP 表示恶龙的攻击力和生命值。
接下来共有 n 行,每行两个正整数 Ai 和 Hi 表示这名勇士的攻击力和生命值。
输出
输出一个整数,表示最少要招揽多少名勇士才能杀死恶龙。
如果不可能杀死恶龙,输出”Fail”。
样例输入
2
1 9
2 2
1 1
样例输出
2
提示
样例解释
两名勇士都招揽。先派出 2 号勇士
第一回合,恶龙生命值变为 8,勇士生命值变为 0。勇士被击败
紧接着派出 1 号勇士
第二回合,恶龙生命值变为 4(两倍伤害),勇士生命值变为 1
第三回合,恶龙生命值变为 0,勇士生命值变为 0。恶龙被杀死
勇士虽然也被击败了,但恶龙已经死了,所以还是胜利了!
数据范围
本题共有 10 个测试点,每个测试点 15 分
对于测试点 1-4 :n<=5,ATK,Hi,Ai<=10,HP<=100
对于测试点 5-7 :n<=1000,ATK,Hi,Ai<=1000,HP<=109
对于测试点 8-10 :n<=105,ATK,Hi,Ai<= 106,HP<=1018
题解
贪心算法的核心就是从局部最优解入手达到全局最优解。
本题中勇士具有血量和伤害两种属性,借鉴Knapsack算法,我们需要选出性价比高即总伤害量高的勇士。
选择方法:计算出每一个勇士的没有攻击加成的总伤害量(总伤害量=回合数*每一回合伤害)。考虑攻击加成,将总伤害量较高的勇士放在较后出场。
#include<iostream>
#include <algorithm>
typedef long long ll;
using namespace std;
const int MAX = 1e5;
ll n, k, atk, hp;
ll a[MAX];
int main() {
cin >> n >> atk >> hp; //输入勇士数,恶龙的伤害、血量
for (int i = 0; i < n; i++) {
ll aa, h; //输入当前勇士的伤害、血量
cin >> aa >> h;
if (h % atk == 0) k = h / atk;
else k = h / atk + 1; //求出当前勇士的回合数
a[i] = aa * k; //算出总伤害量=回合数*每一回合伤害
}
sort(a, a + n); //将各勇士按照总伤害量进行快排
//寻找最优策略(从总伤害量最高的勇士依次往下寻找)
for (int j = 1; j <= n; j++) {
ll hpp = hp;
for (int i = j, l = 1; i >= 1; i--, l++) {
hpp -= a[n - i] * l;
cout << hpp << endl;
}
if (hpp <= 0) {
cout << j;
return 0;
}
}
cout << "Fail";
return 0;
}