/PS 困,不想说废话啦!我要睡觉QWQ
喷水装置
题目描述
有一块草坪,横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<=10000)个点状的喷水装置,每个喷水装置i喷水的效果是让以它为中心半径为Ri的圆都被润湿。请在给出的喷水装置中选择尽量少的喷水装置,把整个草坪全部润湿。
输入描述
第一行输入一个正整数N表示共有n次测试数据。每一组测试数据的第一行有三个整数n,w,h,n表示共有n个喷水装置,w表示草坪的横向长度,h表示草坪的纵向长度。随后的n行,都有两个整数xi和ri,xi表示第i个喷水装置的的横坐标(最左边为0),ri表示该喷水装置能覆盖的圆的半径。
输出描述
每组测试数据输出一个正整数,表示共需要多少个喷水装置,每个输出单独占一行。如果不存在一种能够把整个草坪湿润的方案,请输出0。
样例
输入
2 2 8 6 1 1 4 5 2 10 6 4 5 6 5
输出
1 2
考场思路
看了,跳了。(包不说废话的)
题解报告
读题,题目中确定了喷水器的数目,横纵坐标以及每个喷水器的半径。一,眼看出与区间覆盖很相似,解题思路就往区间覆盖问题上靠。
这个题让我们用圆去覆盖一个长方形,直接把区间变成圆去做肯定是不行的(因为即使是内结圆也无法完全覆盖其对应的正方形),所以我们可以化繁为简,把圆中无用的范围割掉,有效区域是一个长方形。
我用两幅图为大家说明何为有效范围。
如图一,在黄色里的这个圆形,他的有效范围是多少呢?(3,2,1)
其实他的有效范围只有他的圆心,他四周的黄色范围没有撒上水,所以想要全部覆盖,还需要找圆将这个圆都盖住,非常浪费。
如图二,同理,因为红线表明的两条弦左右分别有无效区域,所以有效区域只有中间的蓝色部分。
我们不妨盯紧中间的中轴线,因为有效范围是长方形,可以惊奇的发现这已经变成了一个一维的区间覆盖问题,那现在的问题是这个区间的左右端点该怎么确认。
如图2.1,通过观察,我们已知R,H,需求X,这个小学二年级的知识点我就不多说了。
有聪明的宝宝可能问
像上面这种情况,右端点咋办。
我只能说,虽然求出来的是错误的数,但其实不影响,这种时候不用去管右端点具体在哪里了,肯定能选出一个超过W的。
那区间覆盖问题我就不多说了,毕竟大家都会
AC代码
困死了有的细节没处理好
#include<bits/stdc++.h>
using namespace std;
struct Q{
double l,r;
}p[10005];
double t,w,h,n,r[10001],x[10001],a,b,pos,s,ans;
int cnt;
bool cmp(Q a,Q b){
return a.l<b.l;
}
int main(){
cin>>t;
while(t--){
pos=0,ans=0,s=1,cnt=0;
cin>>n>>w>>h;
for(int i=1;i<=n;i++){
cin>>a>>b;
if(b>=h/2.0){
p[++cnt].r=a+(sqrt(b*b-h*h/4));
p[cnt].l=a-(sqrt(b*b-h*h/4));
}
}
sort(p+1,p+cnt+1,cmp);
while(pos<w){
double maxx=0;
for(int i=s;i<=cnt&&p[i].l<=pos;i++){
maxx=max(maxx,p[i].r);
s++;
}
if(maxx==0){
cout<<0<<endl;
break;
}
pos=maxx;
ans++;
if(pos>=w){
cout<<ans<<endl;
break;
}
}
}
return 0;
}