暑期集训之喷水装置(二)

喷水装置(二)

时间限制: 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
来源
《算法艺术与信息学竞赛》
上传者
张云聪

又是一道贪心题,表示贪心题确实不好做QAQ。考虑的因素不少,并且贪心思想也是难点,看了半天,也是最后懂了怎么做了,这类题真的是做一个会一个啊,这道题其实我开始的时候理解了题意了,但不知道代码怎么实现,所以不会做,不过看过学长博客后知道怎么做了,这道题其实就是从第一个喷水装置开始,分别把它于上边界的起始交点坐标和上边界的终点交点坐标给计算出来(用勾股定理来求),然后如果这个交点坐标没有小于一开始的0,则跳过此喷水装置,如果全部跳过,则代表不可能铺满,所以最后base也就一直是0。最后输出0,当然,如果其中一个小于0了,这个时候就开始重新排布了(说了半天,估计也不是很好懂,还是在代码里面详细解释吧)代码如下:

#include<stdio.h>  
#include<algorithm>  
#include<math.h>  
using namespace std;  
int ans;//喷水装置的个数  
double base;//这个是上界起始坐标  
double maxd;//这个是上界终点坐标  
struct node  
{  
    double st,end,x,r;  
}data[10022];//用结构体来定义每个装置  
double cal(double x,double z)//这里算是一个勾股定理函数,用来计算上界的起始点和终点  
{  
    double m;  
    m=sqrt(x*x-z*z);  
    return m;  
}  
int main()  
{  
    int t;
    int n,w,h;
    double k;
    while(scanf("%d",&t)!=EOF)
    {
    	while(t--)
    	{
    		scanf("%d%d%d",&n,&w,&h);
    		h=h/2;
    		for(int i=0;i<n;i++)
    		{
					scanf("%lf%lf",&data[i].x,&data[i].r);
					if(data[i].r<=h)//这里的话是一个排除操作,意思是把一些喷水半径小于草坪宽的一半的删除 ,因为如果这个装置喷水半径小于宽的一般的话它无论如何都不可能喷满整个草坪的,所以索性就排除掉了这些装置,不过事实证明这道题其实不这样考虑也是正确的,总的来说出的不是很严谨吧。 
					{
						n--;
						i--;
					}
				else
				{
				k=cal(data[i].r,h);//勾股定理 
    			data[i].st=data[i].x-k;//这里也就是一个确定上界起始点的操作,可以自己画图分析下是什么原理,具体就不解释了,很简单 
    			data[i].end=data[i].x+k;//同理,这里是上界终点 
    		}
    	}
    		base=0;//这里归零也是为了和草坪起点一直,因为题上默认草坪起点是0 
    		ans=0;
    		for(int i=0;i<n;i++)
    		{   
    			if(w<=base)//这里的意思是如果草坪的总长度小于起始点(下面的一个操作让这个变量变成了一个装置的上界终点),则结束循环 
    			{   
    				break;
				}
				else
				{   maxd=0;//这个变量是一个临时储存上界终点的变量,方便变量交换 
					for(int j=0;j<n;j++)
					{
						if(data[j].st<=base)//这里就是我题目介绍中说的那样,如果装置的上界起始点在草坪起始点或者说另一个装置的上界终点的右边的话就认为它可以帮助铺满整个草坪 
						{
							if(data[j].end>maxd)//这里是一个大小比较,意思就是在满足上述条件的装置里面选出来范围最大的那个,然后记录它的各种坐标 
							maxd=data[j].end;
						}
					}
					base=maxd;//这步操作也挺有用的,其实就是当你选中开始那个最大的那个后,整个草坪实际上也就缩小了,草坪的起始点成了上面选出来的那个最大的喷水装置的上界终点了,然后装置数目加一,继续往后面进行 不是很懂得可以返回去看看48行的那个解释,联系起来理解 
					ans++;//这里虽然都是加一的操作,但如果不符合情况的,最后还是不会输出这个数的,所以这里不用考虑太多 
				}
			}
			if(base<w)//这里的意思是,如果出现了最后得到的那个上界终点小于草坪的总长,意味着铺不满,输出0,否则输出个数 
			printf("0\n");
			else
			printf("%d\n",ans);
		}		
	}
    return 0;  
}  //这道题总的来说如果你懂了就很简单,当然我相信看完我的解释应该也都懂了啥意思了,我已经尽我能力解释了QAQ 


总之,每道贪心题都要认真对待ORZ



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值