nyoj 12 喷水装置(二)

来源:互联网 发布:剑指offer c语言 编辑:程序博客网 时间:2024/05/17 23:12

喷水装置(二)

时间限制: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
样例输出
12
又一道贪心,早晚征服它!!!花了好几个小时才ac,错了7次...但能ac真的很开心!  纯自己的思路,大神路过勿喷。
#include<stdio.h>#include<math.h>#include<algorithm>using namespace std;struct record{double start;//每个喷水装置覆盖范围的起点 double end;//覆盖范围的终点 }num[100100];bool cmp(record a,record b){if(a.start!=b.start)return (a.start<b.start);elsereturn (a.end>b.end);}//按起点升序排列,如果起点相同,按终点降序排列 int main(){int x[100100],r[100100];//x表示喷水装置坐标,r表示覆盖半径 int t,n,w,h;int m; int i,j,sum;//sum计数变量,i,j循环变量int contact,k,l,g; //contact英文表示接点,这里表示接上一装置且最优的装置。k,l,g是一个判断变量。 double he,juli;//juli表示两个相邻喷水装置的终点之差,he表示当前喷水装置所能覆盖的长度 scanf("%d",&t);while(t--){scanf("%d%d%d",&n,&w,&h);k=l=0;m=0;for(i=0;i<n;i++){scanf("%d%d",&x[i],&r[i]);if(r[i]>(double)h/2){num[m].start=x[i]-sqrt(r[i]*r[i]-(double)h*h/4);if(num[m].start<0){num[m].start=0;} num[m].end=x[i]+sqrt(r[i]*r[i]-(double)h*h/4);//把覆盖半径大于纵长一半的起点终点求出来     if(num[m].start==0)//判断有没有起点从0开始的     k=1;    if(num[m].end>=w)//判断有没有终点大于或等于草坪长度的     l=1;    m++;}}if(k==0||l==0)//如果不满足起点=0,终点>=w printf("0");else{sort(num,num+m,cmp);    sum=0;contact=1;    for(i=0;i<m;i+=(contact-i))    {    juli=g=0;     he=num[i].end;//当前所用装置覆盖长度     sum++;    if(he>=w)break;//找出 最大距离     for(j=i+1;j<m;j++)    {    if((num[j].start<=num[i].end)&&(num[j].end-num[i].end>juli))//如果该装置起点能接上且大于上一个终点         {        juli=num[j].end-num[i].end;contact=j; //第j个装置最优g=1;//可以接上 -->赋值g为1         }    }    if(g==0)//遍历所有装置都不能接上上一个装置     break;    }    if(he>=w)    printf("%d",sum);    else    printf("0");}printf("\n"); }return 0;} 

1 0
原创粉丝点击