NYOJ--12--喷水装置(二)

来源:互联网 发布:mv软件 编辑:程序博客网 时间:2024/05/18 01:38

喷水装置(二)

时间限制:3000 ms  |  内存限制:65535 KB
难度:4
 
描述
有一块草坪,横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<=10000)个点状的喷水装置,每个喷水装置i喷水的效果是让以它为中心半径为Ri的圆都被润湿。请在给出的喷水装置中选择尽量少的喷水装置,把整个草坪全部润湿。
 
输入
第一行输入一个正整数N表示共有n次测试数据。
每一组测试数据的第一行有三个整数n,w,h,n表示共有n个喷水装置,w表示草坪的横向长度,h表示草坪的纵向长度。
随后的n行,都有两个整数xi和ri,xi表示第i个喷水装置的的横坐标(最左边为0),ri表示该喷水装置能覆盖的圆的半径。
输出
每组测试数据输出一个正整数,表示共需要多少个喷水装置,每个输出单独占一行。
如果不存在一种能够把整个草坪湿润的方案,请输出0。
样例输入
22 8 61 14 52 10 64 56 5
样例输出
1

2

思路:这是一道区间覆盖问题,关键就在于将其转化为 区间覆盖类型。需要求出每个喷头的实际覆盖长度。公式l=sqrt(r*r-(h/2)*(h/2));

由此算出每一个喷头覆盖区间的两端点,再利用区间覆盖做题就可以了。其中 要注意利用这个公式计算的时候 所得的l是一个实数,不能用整形。

ac代码:

#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#define MAX 10010using namespace std;struct node{double left,right;}edge[MAX];bool cmp(node a,node b){if(a.left==b.left)return a.right>b.right;elsereturn a.left<b.left;}int main(){int Tcase;scanf("%d",&Tcase);while(Tcase--){int n;int w,h,m=0;scanf("%d%d%d",&n,&w,&h);for(int i=1;i<=n;i++){int x,r;scanf("%d%d",&x,&r);if(r<h/2)//筛选符合条件的边。 continue;double l;//有效覆盖区间;l=sqrt(r*r-(h/2.0)*(h/2.0));edge[++m].left=x-l;edge[m].right=x+l;if(edge[m].left<0)edge[m].left=0;if(edge[m].right>w)edge[m].right=w; }sort(edge+1,edge+m+1,cmp);double len=0;int cnt=0;for(int i=1;i<=m;i++)//区间覆盖 {double temp=len; for(int j=i;j<=m;j++){if(edge[j].left<=len&&edge[j].right>len){temp=max(temp,edge[j].right);}}if(temp>len){len=temp;cnt++;}}if(len-w<0)printf("0\n");elseprintf("%d\n",cnt);}return 0;} 


0 0
原创粉丝点击