【题目描述】
llg 是一名快乐的农民,他拥有一个很大的农场,并且种了各种各样的瓜果蔬菜,到了每年秋天,他就可以把所有蔬菜水果卖到市场上,这样他就可以获利。但今年他遇到了一个难题——有许多鸟来到了他的农场偷吃他的瓜果蔬菜。不知所措的 llg 只好求助于 jump,万能的 jump 于是给了 llg 一些稻草人(据说可以驱鸟)。每个庄稼都可以看做是坐标系里面的一个点,当它处于某个稻草人的范围内时就可以视为被保护。可是每个稻草人的辐射范围有限,根据测定,每个稻草人的辐射范围都是一个半径为 R 的圆,llg 很懒,所以他只打算把稻草人放在坐标系的 x 轴上,而任何庄稼(x,y)都满足 y>0。图中的小红点就是庄稼,蓝点即稻草人放的位置。现在请你来帮助 llg设计一个方案,用尽可能少的稻草人来保证所有庄稼都是安全的。若存在无法覆盖的庄稼或者 jump 给的稻草人不够覆盖所有庄稼,请输出-1。
【输入数据】每个测试点含多组数据每组数据第一行包含 n,R,C;分别表示庄稼的数量、稻草人的最大覆盖半径,命题人:黎锦灏稻草人的数量。接下来 n 行,每行包括两个数 xi,yi 表示一个点的坐标输入以“0 0 0”结尾 【输出数据】对于每组数据,请输出最小要用多少稻草人,才能保证覆盖所有庄稼。若无法覆盖或数量不够,请输出-1。
【数据约定】
对于 30%的数据,1<=n<=3000对于 100%的数据, 1<=n<=50000,1<=数据组数<=10,其余数据均保证不会超过 int的范围
思路:
对于任意一个庄稼 我们可以很轻松的得出能覆盖到此庄稼的的稻草人位置 即圆心位置
令庄稼位置为(x,y)
则稻草人的横坐标范围为[x-sqrt(r*r-y*y),x+sqrt(r*r-y*y)] 边界就是庄稼恰好在圆心上
我们求出每个庄稼所对应的圆心范围后 题目就转化成了:
有若干可能互相重合的线段 求最少的点数使每条线段上至少有一点
然后按横坐标排序
贪心 对于排序之后的线段 取最右端为最优(尽可能覆盖到多的点)
具体见代码吧
CODE:
View Code1 #include2 #include 3 #include 4 #include 5 #define go(i,a,b) for(register int i=a;i<=b;i++) 6 #define db double 7 #define M 50000+10 8 using namespace std; 9 int read()10 {11 int x=0,y=1;char c=getchar();12 while(c<'0'||c>'9') { if(c=='-') y=-1;c=getchar();}13 while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}14 return x*y;15 }16 int n,r,m,x,y,ans;17 bool fg;18 struct node {db l,r;}a[M];19 bool cmp(node u,node v){ if(u.l!=v.l) return u.l r||fg) {fg=1;continue ;}32 db k=(db)sqrt(r*r-y*y);33 a[i].l=(db)x-k;34 a[i].r=(db)x+k;35 }36 if(fg) {puts("-1");continue ;}37 sort(a+1,a+n+1,cmp);38 db nw=a[1].r;39 go(i,2,n)40 {41 if(a[i].l>nw) {ans++;nw=a[i].r;}42 else nw=min(nw,a[i].r);43 }44 if(ans>m) {puts("-1");continue ;}45 printf("%d\n",ans);46 }47 return 0;48 }