题解 | #幻兽防御战#
幻兽防御战
https://www.nowcoder.com/practice/13a2e8a30e414f3f964548a834c26f7c
题目链接
题目描述
小红守卫遗迹,有 只怪兽冲向遗迹。第
只怪兽的初始距离为
,移动速度为
,其到达遗迹的时间为
。
小红每分钟只能发射一次弩箭。在第
分钟开始的瞬间(
),小红可以消灭一只尚未到达遗迹的怪兽。
如果存在某只未被消灭的怪兽满足
,则该怪兽会在小红准备好第
次射击(即第
分钟开始时)或之前抵达并摧毁遗迹,防守立即失败。
请计算小红在遗迹被摧毁前,最多能消灭多少只怪兽。
解题思路
这是一个典型的贪心问题。
-
计算到达时间: 对于每只怪兽,其到达遗迹的时间为
。
-
贪心策略: 为了尽可能多地消灭怪兽,小红应该优先消灭那些最早到达遗迹的怪兽。 我们将所有怪兽按照到达时间
从小到大进行排序。
-
模拟射击过程: 设定射击序号为
,从
开始计数。
- 第
次射击(在
时刻):检查当前到达时间最短的怪兽。如果
,防御失败。否则消灭该怪兽。
- 第
次射击(在
分钟开始时):检查此时未被消灭的怪兽中到达时间最短的那只(即排序后的第
只怪兽)。
- 如果该怪兽的到达时间
,说明在小红准备好这次射击时,怪兽已经到达了遗迹,防御失败。
- 如果
,则可以消灭这只怪兽,继续下一轮射击。
- 第
-
数值处理: 为了避免浮点数精度问题,比较
可以转化为整数比较:
。 注意
可能会超过
,因此在 C++ 和 Java 中需要使用
long long或long。
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 定义怪兽结构体
struct Monster {
long long d, s;
};
// 按到达时间排序:d1/s1 < d2/s2 <=> d1 * s2 < d2 * s1
bool compareMonsters(const Monster& a, const Monster& b) {
return a.d * b.s < b.d * a.s;
}
int main() {
int n;
cin >> n;
vector<long long> d(n), s(n);
for (int i = 0; i < n; ++i) cin >> d[i];
for (int i = 0; i < n; ++i) cin >> s[i];
vector<Monster> monsters(n);
for (int i = 0; i < n; ++i) {
monsters[i] = {d[i], s[i]};
}
// 按照到达时间升序排序
sort(monsters.begin(), monsters.end(), compareMonsters);
int ans = 0;
for (int k = 0; k < n; ++k) {
// 判断第 k 只怪兽是否在第 k 次射击前或射击瞬间到达
// 比较 D_k / S_k <= k
if (monsters[k].d <= (long long)k * monsters[k].s) {
break;
}
ans++;
}
cout << ans << endl;
return 0;
}
import java.util.*;
public class Main {
// 怪兽类
static class Monster {
long d, s;
Monster(long d, long s) {
this.d = d;
this.s = s;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
long[] d = new long[n];
long[] s = new long[n];
for (int i = 0; i < n; i++) d[i] = sc.nextLong();
for (int i = 0; i < n; i++) s[i] = sc.nextLong();
List<Monster> monsters = new ArrayList<>();
for (int i = 0; i < n; i++) {
monsters.add(new Monster(d[i], s[i]));
}
// 排序规则:d1/s1 < d2/s2 即 d1*s2 < d2*s1
Collections.sort(monsters, (a, b) -> {
long val1 = a.d * b.s;
long val2 = b.d * a.s;
return Long.compare(val1, val2);
});
int ans = 0;
for (int k = 0; k < n; k++) {
Monster m = monsters.get(k);
// 检查 D_k <= k * S_k
if (m.d <= (long) k * m.s) {
break;
}
ans++;
}
System.out.println(ans);
}
}
def solve():
# 读取怪兽数量
n = int(input())
# 读取初始距离
d_list = list(map(int, input().split()))
# 读取移动速度
s_list = list(map(int, input().split()))
monsters = []
for i in range(n):
monsters.append((d_list[i], s_list[i]))
# 按照到达时间 d/s 升序排序
# Python 自动处理大整数,可以直接使用 d/s 排序或用 d * other_s 比较
monsters.sort(key=lambda x: x[0] / x[1])
ans = 0
for k in range(n):
d, s = monsters[k]
# 判断第 k 只怪兽是否在第 k 分钟准备射击时或之前到达
if d <= k * s:
break
ans += 1
print(ans)
solve()
算法及复杂度
- 算法:贪心算法 + 排序。
- 时间复杂度:
。主要开销在于对
只怪兽的到达时间进行排序。
- 空间复杂度:
。需要存储每只怪兽的初始距离和速度。
