UVa 10382 - Watering Grass(贪心算法,区间覆盖问题)

该博客讨论了如何应用贪心算法解决UVa 10382问题,即在覆盖一定长度草地的区间覆盖问题。通过将问题转化为区间覆盖,舍去无法覆盖的洒水器,并按覆盖范围升序排列,逐步找到能覆盖最远区域的洒水器,以求得覆盖整个草地所需的最小洒水器数量。如果无法覆盖所有草地,则输出-1。

Problem E
Watering Grass
Input:
standard input
Output: standard output
Time Limit: 3 seconds

n sprinklers are installed in a horizontal strip of grass l meters long andw meters wide. Each sprinkler is installed at the horizontal center line of the strip. For each sprinkler we are given its position as the distance from the left end of the center line and its radius of operation.

What is the minimum number of sprinklers to turn on in order to water the entire strip of grass?

Input

Input consists of a number of cases. The first line for each case contains integer numbersn, l and w with n <= 10000. The next n lines contain two integers giving the position of a sprinkler and its radius of operation. (The picture above illustrates the first case from the sample input.)

 

Output

For each test case output the minimum number of sprinklers needed to water the entire strip of grass. If it is impossible to water the entire strip output -1.

Sample input

8 20 2

5 3

4 1

1 2

7 2

10 2

13 3

16 2

19 4

3 10 1

3 5

9 3

6 1

3 10 1

5 3

1 1

9 1

 

Sample Output

6

2

-1


(Regionals 2002 Warm-up Contest, Problem setter: Piotr Rudnicku)

 

思路:

贪心思想,将问题转化为区间覆盖问题,将草地的上边界作为要覆盖的区间,计算出每个洒水器覆盖的区间范围,不能覆盖的舍去,然后将洒水器按覆盖范围的左边界升序排列。

要覆盖的最右边的点rightmost的初始值为0,遍历洒水器,找一个能覆盖住rightmost且覆盖范围的右边界最大的洒水器,然后将该洒水器覆盖的右边界作为新的rightmost,重复刚才的过程,直到覆盖整个草地。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;

#define MAX_SIZE 10000

struct Sprinkler
{
	double left;
	double right;
	bool operator < (const Sprinkler &s) const
	{
		return left < s.left;
	}
}sprinklers[MAX_SIZE+5];

int WaterTheGrass(int m, int l)
{
	double rightmost = 0.0;
	int count = 0;
	int i, j;
	for (i = 0; i < m; i = j)
	{
		if (sprinklers[i].left > rightmost) break;
		for (j = i+1; j < m && sprinklers[j].left <= rightmost; ++j)
		{
			if (sprinklers[j].right > sprinklers[i].right)
			{
				i = j;
			}
		}
		++count;
		rightmost = sprinklers[i].right;
		if (rightmost >= l) break;
	}
	if (rightmost >= l)
	{
		return count;
	}
	return -1;
}

int main(void)
{
	int n, l;
	double w;
	while (cin >> n >> l >> w)
	{
		w /= 2.0;
		int i, m = 0;
		for (i = 0; i < n; ++i)
		{
			int p, r;
			scanf("%d%d", &p, &r);
			if (r > w)
			{
				double halfCoveredLen = sqrt((double)r*r - w*w);	//注意转化为double型,错了好几次...
				sprinklers[m].left = (double)p - halfCoveredLen;
				sprinklers[m++].right = (double)p + halfCoveredLen;
			}
		}
		sort(sprinklers, sprinklers+m);
		cout << WaterTheGrass(m, l) << endl;
	}
	return 0;
}
欢迎转载,请尊重作者,转载请标明出处: http://blog.csdn.net/code_pang/article/details/17919533

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

庞老板

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值