贪心算法训练(六)——喷水装置(区间覆盖问题)
1. 问题描述
长 L 米,宽 W 米的草坪里装有 n 个浇灌喷头,每个喷头都装在草坪的中心线上(离两边各 W/2 米)。我们知道每个喷头的位置(离草坪中心线左端的距离),以及它能覆盖到的浇灌范围。请问如果要同时浇灌整块草坪,最少需要打开多少个喷头?
2. 输入格式
输入包含若干测试数据
每组数据的第一行是整数n、L 和 W 的值,其中 n <= 10000
接下来的 n 行,每行包含 2 个整数,给出一个喷头的位置 x 和浇灌半径 r
3. 输出格式
对每组测试数据输出一个数字,表示要浇灌整块草坪所需喷头数目的最小值。如果所有喷头都打开还不能浇灌整块草坪,则输出 -1
4. 样例输入
3 8 20 2 5 3 4 1 1 2 7 2 10 2 13 3 16 2 19 4 3 10 1 3 5 9 3 6 1 3 10 1 5 3 1 1 9 1
5. 样例输出
6 2 -1
6. 思路分析
录入数据的同时计算出它的有效灌溉半径(勾股定理),start = x – sqrt(r^2 – (w/2)^2),end = x + sqrt(r^2 – (w/2)^2),排序,在选定位置范围内,依次寻找最大的 end。
7.代码(直接复制数据可能有问题,建议手动输入)
#include <iostream> #include <cstring> #include <cmath> #include <cstdio> #include <algorithm> using namespace std; int n,cnt,L,h,x,r; struct SEG { double x,y; }a[20005]; bool cmp(const SEG& x,const SEG& y) { return x.x < y.x; } void Read() { cin>>n>>L>>h; cnt = 0; for(int i = 1;i <= n;i++) { cin>>x>>r; if(r <= h/2) continue; cnt ++; a[cnt].x = x - sqrt(r*r - h*h/4.0); a[cnt].y = x + sqrt(r*r - h*h/4.0); } } void solve() { double t= 0; int ans = 0,bj = 1,i = 1; while(t < L) { ans ++; double s = t; for(;a[i].x <= s && i<= cnt;i++) if(t < a[i].y) t = a[i].y; if(t == s && s < L) { cout<<-1<<endl; bj = 0; break; } } if(bj) cout<<ans<<endl; } int main() { ios::sync_with_stdio(false); int T; cin>>T; while(T--) { Read(); sort(a+1,a+cnt+1,cmp); solve(); } return 0; }