NYOJ 喷水装置(二)贪心

喷水装置(二)

时间限制: 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。
样例输入
2
2 8 6
1 1
4 5
2 10 6
4 5
6 5
样例输出
1
2


思路:把长方形问题转化成了区间A(线段A),求怎么用最少的小线段(L1,L2,L3,,,,,,Ln)才能全部覆盖线段A的问题 
本题出的很好,考验人的发散思维,,,,,come  on!!!!!!!!

#include<stdio.h> 
#include<algorithm> 
#include<math.h> 
using namespace std; 
const int MAX=10001;
struct p{ 
double left,right; 
}a[MAX]; 
bool cmp(struct p a,struct p b){ 
return a.left<b.left; 



int main() 

  int i,j,num,len,wight,times,count,biaoji; 
  double wight_2;    
  scanf("%d",&times); 
  while(times--) 
  { 
    biaoji=1; 
    count=0; 
    scanf("%d%d%d",&num,&len,&wight); 
    wight_2=wight/2.000000; 
    for(i=0;i<num;i++) 
    { 
      int x,r; 
      double temp_w; 
      scanf("%d%d",&x,&r);
      temp_w=sqrt(r*r-wight_2*wight_2); 
      if(temp_w>0)       // 排除r<=wight_2情况
      {                             //(a[0].right减去a[0].left)形成线段L0,最终 形成小线段(L1,L2,L3,,,,,,Ln) 
      a[i].left=x-temp_w;        
      a[i].right=x+temp_w;            
      }                                  
    } 
    sort(a,a+num,cmp);   //按照小线段L的左端点从小到大排序   
    double Max=0,sum=0;  //在使用本装置之前已经被覆盖的长度0 
    while(sum<len) 
    { 
      Max=0; 
      for(i=0;i<num&&a[i].left<=sum;i++) //本for循环每次找出a[i].left<=sum和 覆盖长度a[i].right-sum最长的一个; 
      {                                     
      if(a[i].right-sum>Max)Max=a[i].right-sum; 
      } 
      if(Max==0){biaoji=0; break; }//若有一次为0,表示找不到这条覆盖的线,也就是永远填满不了这条线 
      else{ count++; sum+=Max; } 
    } 
    if(biaoji) printf("%d\n",count); 
    else printf("0\n"); 
 } 
return 0; 


第二种解法:额,,,是别人的代码,,,不懂,,,坐等大神回复啊


#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct p
{
double x;
double r;
}a[10004];
int cmp(p a,p b){return a.r<b.r;}//按照半径进行升序排列,排列后进行运算a[i].x=f-sqrt(g*g-h*h/4.0);a[i].r=sqrt(g*g-h*h/4.0)+f;的                                                                     //顺序就完全乱了,后面的还怎么做??????
int main()
{
int t,n,w,h,i,j,x,r;
int f,g,l;
double max,sum;
scanf("%d",&t);
while(t--)
{
   scanf("%d%d%d",&n,&w,&h);
   for(i=0,j=0;i<n;i++)
   {
    scanf("%d%d",&x,&r);
    if(r>h/2.0)//排除r<=h/2.0无用情况 
    {
    a[j++].x=x;
    a[j-1].r=r;
    }
   }
   if(w<=h&&j==0){printf("0\n");continue;}
   if(w<=h&&j>0){printf("1\n");continue;}
   sort(a,a+j,cmp);//按照半径从小到大排序
   for(i=0;i<j;i++)
   {
    f=a[i].x;
    g=a[i].r;
    a[i].x=f-sqrt(g*g-h*h/4.0);//(a[0].right-a[0].left)形成线段L0,
    a[i].r=sqrt(g*g-h*h/4.0)+f;   //a[i].x为L0的左端点坐标 , a[i].r为L0的左端点坐标
   } 
   l=0;max=0;sum=0;
   while(sum<w)
   {
    for(i=0;i<j;i++)
    {
     if(a[i].x<=sum&&(a[i].r-sum>max))
       max=a[i].r-sum;
    }
    if(max==0)//注意这个地方,没有这个判断的话会超时
    {
      l=0;
      break;
    }
    sum+=max;
    l++;
    max=0;
   }
printf("%d\n",l);


}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值