
黑塔女士的普通攻击可以对一名敌人造成一点伤害。此外,黑塔女士的天赋,会在敌人的生命值首次降低到初始值的二分之一(向下取整)时,立即发动追加攻击,对所有敌人造成一点伤害。
追加攻击造成的伤害可以继续触发追加攻击,且多个敌人的生命值同时下降到二分之一时,每个敌人都可以触发一次追加攻击。
现在有许多敌人,黑塔女士应该如何用最少的普通攻击消灭所有敌人呢?
n整数数组a, 表示有n名敌人,第i名敌人初始生命值为a[i]。[5, 6]
7 // 需要普通攻击0号敌人3次,1号敌人4次。
[1, 2, 3, 4, 5]
1 // 对0号敌人或者对1号敌人进行一次普通攻击即可。
[1, 3, 6]
3 // 对初始生命为6的敌人进行3次普通攻击即可。想到了一种贪心的思路,将数组从小到大排序后,依次攻击,每个都攻击到触发为止,攻击完一轮,所有可能的追加攻击都触发过了,再遍历一轮补刀。但这个思路不对,示例中的第3组数据就过不了。
求大佬解答。
谢谢各位大佬积极讨论。目前看到比较多的思路是先把超过n的敌人的生命值削减到n,然后依次攻击距离最接近半血的敌人。整理了一下,得到代码如下:
long long minimumNormalAttack(vector<int> nums)
{
long long normalAttackCount = 0;
int n = nums.size();
vector<pair<int, int>> enemies;
for (int i = 0; i < n; i++)
{
enemies.push_back(make_pair(nums[i], nums[i])); // 每个pair的first是当前血量,second是初始血量
}
int aoeCount = 0; // 统计已经触发过AOE的次数
for (int i = 0; i < n; ++i)
{
auto &enemy = enemies[i];
if (enemy.second > n) // 如果敌人的初始血量大于n, 这些超过n的血量值早晚要用普攻打, 所以先进行这些普攻, 有利于更早触发AOE
{
normalAttackCount += enemy.second - n;
enemy.first = n;
if (n <= enemy.second / 2)
{
aoeCount++;
}
}
}
auto compare = [](pair<int, int> a, pair<int, int> b)
{
// 比较哪个敌人的当前血量更接近初始值的一半, 假设传入参数不会有血量小于初始值一半的情况
return a.first - a.second / 2 > b.first - b.second / 2;
};
// 其实在vector里直接排序也可以, 但是compare就要考虑到血量小于初始值一半的情况
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(compare)> pq(compare);
for (int i = 0; i < n; ++i)
{
if (enemies[i].first > enemies[i].second / 2)
{
pq.push(enemies[i]);
}
}
while (!pq.empty())
{
// 每次取出当前血量最接近初始值一半的敌人
auto enemyNearestToHalf = pq.top();
pq.pop();
// 考虑已经触发过的AOE能否把这个敌人的血量打到初始值一半以下, 如果不能, 就用普攻打到触发AOE为止
if (enemyNearestToHalf.first - aoeCount > enemyNearestToHalf.second / 2)
{
normalAttackCount += enemyNearestToHalf.first - enemyNearestToHalf.second / 2 - aoeCount;
}
++aoeCount;
// 剩余多少血就不用管了, 只要所有AOE都触发一遍, 剩余的血量都会被打掉
}
return normalAttackCount;
}当然我也没有标准答案或者判题程序,无法验证各个思路的正确性。欢迎大家继续讨论。