喷水装置
链接:vjudge 喷水装置
题目描述
长 L 米,宽 W 米的草坪里装有 n 个浇灌喷头。每个喷头都装在草坪中心线上(离两边各 W/2米)。我们知道每个喷头的位置(离草坪中心线左端的距离),以及它能覆盖到的浇灌范围。
请问:如果要同时浇灌整块草坪,最少需要打开多少个喷头?
输入格式
输入包含若干组测试数据。
第一行一个整数 T 表示数据组数;
每组数据的第一行是整数 n、L 和 W;
接下来的 n 行,每行包含两个整数,给出一个喷头的位置和浇灌半径(上面的示意图是样例输入第一组数据所描述的情况)。
输出格式
对每组测试数据输出一个数字,表示要浇灌整块草坪所需喷头数目的最小值。如果所有喷头都打开也不能浇灌整块草坪,则输出 -1 。
思路
- 题目中喷水装置是一个圆形的范围,为了方便处理可以将它看成一个矩形,左右端点则为圆形与草坪的交点。若两个圆形重合只需判断两个矩形的左端点和右端点大小关系。
- 采取一个贪心的策略,每次都找到一个左端点<=草坪左侧,右端点最大的矩形,如果能找到则将草坪左端点更新矩形的右端点,继续重复这个操作。如果没找到符合的矩形,那么说明无法灌溉整块草坪。
- 为了提高效率,可以在搜索时候判断,将不符合条件的点提前去除(半径小于W/2、右端点<0、左端点>L)。
代码
#include<bits/stdc++.h>
using namespace std;
#define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
typedef pair<double, double> PDD;
int t, n, idx, ans;
double sta, maxr;
double l, w, p, r;
vector<PDD> vpd;
int main() {
io_opt;
cin >> t;
while (t--) {
cin >> n >> l >> w;
w /= 2;
sta = 0, ans = 0;
vpd.clear();
while (n--) {
cin >> p >> r;
if (r <= w) continue;
double tt = sqrt(pow(r, 2) - pow(w, 2));
if (p - tt > l || p + tt < 0) continue;
vpd.push_back({ p - tt,p + tt });
}
sort(vpd.begin(), vpd.end());
while (sta < l && !vpd.empty()) {
idx = -1, maxr = 0;
for (int i = 0; i < vpd.size(); i++) {
if (vpd[i].first <= sta && vpd[i].second > maxr){
maxr = vpd[i].second;
idx = i;
}
}
if (idx == -1) break;
ans++;
sta = maxr;
vpd.erase(vpd.begin() + idx);
}
if (sta < l) cout << -1 << endl;
else cout << ans << endl;
}
return 0;
}```