uva10382装喷头(贪心-变相最小覆盖问题)

n sprinklers are installed in a horizontal strip of grass l meters long and w 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 numbers n, 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

题意
给你一个长和宽都知道的草地,然后给你一些喷头,每个喷头告诉你喷头的位置和喷水的半径(为圆),然后你选择最少的喷头使得整个草地能喷到水。
题解:
(1)题意是要喷到整个草地(长方形),但每个喷头喷水的范围却是圆,那么圆我们只需要考虑以圆和长方体的交点连线与圆点的距离即可(有效长度),因为另一部分圆到达的长度的地方不能完全喷洒到草地到达的长度的整个面积。
(2)那么现在题目就是变为选定最小的喷头,有效范围能覆盖掉草地的长度。看了算法入门经典的高效算法设计的贪心部分,才学到了这种办法,比我之前根据右端点来排序,现在根据左区间从小到大排序要高效很多。
(3)如(2)所说,排好序后,如果最左的左端点大于0,那么肯定是无法覆盖了,那么第一步是从左端点小于0的线段中找到最大右端点k,那么找到后,该右端点就变成左端点了,那么第二次找的时候,之前小于0的就可以不再找了,因为这些当中最大的已经找到了。
(4)从剩下的线段中(除掉小于0的)找到左端点小于k的,并将其中最大右端点更新为左端端点
(5)重复(4)过程直到找到线段右端点大于草地右端点的即结束,当然其中有一个无法更新左端点右端点的,就说明无法继续更新,结束。
ac代码:

#include<iostream>       
#include<cstdlib>      
#include<cstdio> 
#include<cstring>      
#include<cmath>           
#include<string>      
#include<cstdlib>      
#include<iomanip>      
#include<vector>      
#include<list>      
#include<map>      
#include<queue>    
#include<algorithm>
using namespace std;
const int N = 10025;

struct node
{
	double x, y;
}p[N];
bool cmp(node s1, node s2)
{
	return s1.x < s2.x;
}

int main()
{
	double n, m, a, b, q;
	int i,v;
	while (cin>>n>>m>>q)
	{
		i = 0;
		double	h = q / 2.0;
		double k = 0, g = 0;
		v = 0;
		for (int j = 0; j < n; j++)
		{
			scanf("%lf%lf", &a, &b);
			if (b <= h)continue;
			double kkk = sqrt(b*b - h*h);

			p[i].x = a - kkk;
			p[i].y = a + kkk;
			i++;
		}
		sort(p, p + i, cmp);
		if (p[0].x > 0)
		{
			cout << -1 << endl; continue;
		}
		int j = 0,l;
		while (j < i)
		{
			l = j;
			while (p[j].x <= k && j < i)
			{
				if (p[j].y > g)
					g = p[j].y; j++;
			}
			v++;
			if (j == i && g < m){v = 0; break;
		}//忘考虑了这种情况,一直wa,即在此更新中已经考虑掉所有线段但右端点却没到达草地右端点
			if (j == l) {
				
				v = 0; break;
			}k = g;
			if (g >= m)break;
		}if (v)
			cout << v << endl;
		else cout << -1 << endl;

	}
}

猜你喜欢

转载自blog.csdn.net/weixin_43965698/article/details/87859324