【正经题解】Gold King大范围洒洒
2024-02-22 11:34:08
发布于:浙江
111阅读
0回复
0点赞
这道题目的主要思路如下:
对每个喷水装置按照其横坐标排序,同时如果两个装置横坐标相同,则将半径大的放在前面。
遍历排序后的喷水装置,如果当前装置的半径大于等于草坪的高度 h,则该装置能够完全润湿一列。将该装置的左右边界加入备选边界。
按照备选边界的左边界进行升序排序,然后使用贪心策略选择最少的喷水装置,使得草坪被完全覆盖。
#include<bits/stdc++.h>
using namespace std;
// 定义喷水装置的结构体
struct Sprinkler {
double left, right; // 喷水装置的左右边界
};
// 自定义比较函数,用于排序喷水装置
bool compareSprinkler(const Sprinkler& a, const Sprinkler& b) {
return a.left < b.left || (a.left == b.left && a.right > b.right);
}
// 冒泡排序,用于对喷水装置按照左边界进行排序
void bubbleSort(int l, int r, Sprinkler sprinklers[]) {
for (int i = 0; i <= r; i++) {
for (int j = i + 1; j <= r; j++) {
if (sprinklers[i].left > sprinklers[j].left ||
(sprinklers[i].left == sprinklers[j].left && sprinklers[i].right < sprinklers[j].right)) {
swap(sprinklers[i], sprinklers[j]);
}
}
}
}
int main() {
int m;
cin >> m;
while (m--) {
int sum = 0, index = 0;
double x, r, n, w, h;
cin >> n >> w >> h;
Sprinkler sprinklers[10001];
// 读入喷水装置的坐标和半径,筛选符合条件的喷水装置
for (int j = 0; j < n; j++) {
cin >> x >> r;
if (2 * r > h) {
double xr = sqrt(r * r - h * h / 4);
sprinklers[index] = {max(0.0, x - xr), x + xr};
index++;
}
}
// 使用自定义的排序函数对喷水装置进行排序
bubbleSort(0, index - 1, sprinklers);
double begin = sprinklers[0].left, end = sprinklers[0].right;
if (begin <= 0) sum++;
int k = 1;
while (k < index && sprinklers[0].left <= 0) {
if (end >= w) break;
if (k == index - 1) {
sum++;
end = sprinklers[index - 1].right;
break;
}
if (end < sprinklers[k].left) break;
double maxEnd = end;
while (end >= sprinklers[k].left) {
maxEnd = max(maxEnd, sprinklers[k].right);
k++;
}
end = maxEnd;
sum++;
}
if (end < w) sum = 0;
cout << sum << endl;
}
return 0;
}
全部评论 1
#include <bits/stdc++.h>
using namespace std;struct Sprinkler {
double l, r;
Sprinkler(double l = 0, double r = 0) : l(l), r(r) {}
};int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);int m; cin >> m; while (m--) { int n; double w, h; cin >> n >> w >> h; vector<Sprinkler> valid; double half_h = h / 2.0; for (int i = 0; i < n; i++) { double x, r; cin >> x >> r; if (r <= half_h) continue; // 无法到达上下边 double d = sqrt(r * r - half_h * half_h); double l = x - d; double r_bound = x + d; // 截断到 [0, w] 范围内(只保留与草坪 x 轴重叠部分) l = max(0.0, l); r_bound = min(w, r_bound); if (l < r_bound) { valid.emplace_back(l, r_bound); } } // 按左端点升序,左端点相同时右端点降序(贪心需要) sort(valid.begin(), valid.end(), [](const Sprinkler& a, const Sprinkler& b) { if (a.l != b.l) return a.l < b.l; return a.r > b.r; }); double cover = 0.0; // 当前覆盖到的最右位置 int count = 0; int i = 0; int sz = valid.size(); while (cover < w) { double max_r = cover; // 在所有左端点 <= cover 的区间中,找最大右端点 while (i < sz && valid[i].l <= cover) { max_r = max(max_r, valid[i].r); i++; } // 如果没找到能延伸的区间,则断开 if (max_r <= cover) { count = 0; break; } count++; cover = max_r; // 注意:这里不回退 i,因为已处理完所有 l <= old_cover 的区间 } cout << count << '\n'; } return 0;}
1周前 来自 浙江
0





有帮助,赞一个