Coduck贪心联系补题报告

/PS 困,不想说废话啦!我要睡觉QWQ

喷水装置

题目描述

  有一块草坪,横向长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

考场思路

看了,跳了。(包不说废话的)

题解报告

读题,题目中确定了喷水器的数目,横纵坐标以及每个喷水器的半径。一,眼看出与区间覆盖很相似,解题思路就往区间覆盖问题上靠。

这个题让我们用圆去覆盖一个长方形,直接把区间变成圆去做肯定是不行的(因为即使是内结圆也无法完全覆盖其对应的正方形),所以我们可以化繁为简,把圆中无用的范围割掉,有效区域是一个长方形。

我用两幅图为大家说明何为有效范围。

如图一,在黄色里的这个圆形,他的有效范围是多少呢?(3,2,1)

其实他的有效范围只有他的圆心,他四周的黄色范围没有撒上水,所以想要全部覆盖,还需要找圆将这个圆都盖住,非常浪费。

如图二,同理,因为红线表明的两条弦左右分别有无效区域,所以有效区域只有中间的蓝色部分。

我们不妨盯紧中间的中轴线,因为有效范围是长方形,可以惊奇的发现这已经变成了一个一维的区间覆盖问题,那现在的问题是这个区间的左右端点该怎么确认。

如图2.1,通过观察,我们已知R,H,需求X,这个小学二年级的知识点我就不多说了。

有聪明的宝宝可能问

像上面这种情况,右端点咋办。

我只能说,虽然求出来的是错误的数,但其实不影响,这种时候不用去管右端点具体在哪里了,肯定能选出一个超过W的。

那区间覆盖问题我就不多说了,毕竟大家都会

AC代码

困死了有的细节没处理好

#include<bits/stdc++.h>
using namespace std;
struct Q{
	double l,r;
}p[10005];
double t,w,h,n,r[10001],x[10001],a,b,pos,s,ans;
int cnt; 
bool cmp(Q a,Q b){
	return a.l<b.l;
}
int main(){
	cin>>t;
	while(t--){
		pos=0,ans=0,s=1,cnt=0;
		cin>>n>>w>>h;
		for(int i=1;i<=n;i++){
			cin>>a>>b;
			if(b>=h/2.0){
				p[++cnt].r=a+(sqrt(b*b-h*h/4));
				p[cnt].l=a-(sqrt(b*b-h*h/4));
			}
		}
		sort(p+1,p+cnt+1,cmp);
		while(pos<w){
			double maxx=0;
			for(int i=s;i<=cnt&&p[i].l<=pos;i++){
				maxx=max(maxx,p[i].r);
				s++; 
			}			
			if(maxx==0){
				cout<<0<<endl;
				break;
			}
			pos=maxx;
			ans++;
			if(pos>=w){
				cout<<ans<<endl;
				break;
			}
		}
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值