喷水装置(二)

喷水装置(二)

时间限制: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

此题是典型的贪心法 即将每个范围都转化成有效范围 即对应区间上的真实范围(也就是x±根号下r^2-(h/2)^2) 超过了范围的直接记为边界

然后每次都去找当前max中所能延伸的最大区间即贪心思想

#include<iostream>
#include<string>
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
class water
{
public:
	double x;
	double realR;
	double r;
	double left;
	double right;
};
bool comp(water x, water y)
{
	if (x.left != y.left) return x.left < y.left;
	else return x.right > y.right;
}
int main()
{
	int N, n, sum, i, k; double w, h, x, wetS, max, range;
	cin >> N;
	while (N--)
	{
		cin >> n >> w >> h;
		sum = 0; wetS = 0;
		water *nice = new water[n];
		for (i = 0; i < n; i++)
		{
			cin >> nice[i].x >> nice[i].r;
			if (nice[i].r <= (h / 2)) { i--; n--; }
			else
			{
				nice[i].realR = sqrt(pow(nice[i].r, 2) - pow(h / 2, 2));
				//计算真实范围
				nice[i].left = nice[i].x - nice[i].realR; if (nice[i].left < 0) nice[i].left = 0;
				nice[i].right = nice[i].x + nice[i].realR; if (nice[i].right>w) nice[i].right = w;
				//超过了边界的直接记为边界
			}
		}
		sort(nice, nice + n, comp);//这个排序很好用

		max = 0; range = 0;

		//如果第一个点未能覆盖到0处 肯定是不能浇灌完所有的区间
		if (nice[0].left != 0);
		else
		{
			//max就是当前所能找到覆盖最大的区间
			while (max < w)
			{
				range = max;
				for (i = 0; i < n&&nice[i].left<=max; i++)
				{
					if (nice[i].right>range) { range = nice[i].right; }
					//不断的去延伸 要是循环结束后range未变 即延伸出现了断点 所以就直接宣布失败
				}
				if (max != range) { max = range; sum++; if (max == w) { break; } }
				else { sum = 0; break; }
			}
		}
		 cout << sum << endl;
	}
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值