UVa 10382 - Watering Grass(区间覆盖问题)

UVa 10382 - Watering Grass(区间覆盖问题)

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
9 1
Sample Output
6
2
-1

题目大意:

一块长方形的地,有一些小喷泉给浇水,每个喷泉浇水的范围是一个圆形,给定长方形的长和宽,还有n个喷泉的位置,和半径,问最少需要多少个喷泉才能把整块地全部覆盖了。

解题思路:

需要稍微变形一下,就是典型的区间覆盖问题了,只需预处理一下每一个喷泉所能浇得地得左右范围
在这里插入图片描述

这个黄色得部分这个喷泉所能浇灌的“极限”,当然还能再浇一小块,但是它不能全浇啊 所以不算数,那我们怎么求呢?
在这里插入图片描述
(这个图画的有点low)
我们只要求出x 然后让这个圆心的位置x0 + x x0-x就是他的左右范围了。
x2=r2 - (w/2)2
接下来就是区间覆盖问题了,简单介绍一下

区间覆盖:

给定一个区间[left,right]. 和一些元素点,每个点都有个左端点l[i],右端点r[i],问最少取多少个元素能把整个区间覆盖了
我们按右端点从大到小进行排序,每次从头找l[i]<=left &&r[i]>left,因为我们是按右端点从从大到小排序的,所以这个点一定是符合条件右端点最远的点,就是一个贪心的思想。
在这里插入图片描述
这时候我们更新 left为r[i],因为前面的已经可以被覆盖了就不用考虑了,一直更新到 left>=right位置

while(left<right)
		{
			int i=0;
		//	cout<<"s"<<endl;
			for( i=0;i<cnt;i++)
			{
				if(a[i].left<=left&&a[i].right>left)
				{
					num++;
					left=a[i].right;//更新区间
					break;
				}
			}
			if(i==cnt)///找了一圈没有合适的
			{
				break;
			}
		}

如果 i=cnt就说明这所有的元素没有一个点符合条件,所以就不可能覆盖掉整个区间,直接退出,最后判断一下 left<right ?

  • 注意:
    这个题有个地方气人,
			double pos,r;
			cin>>pos>>r;

这个地方我一开始用的int 然后wa wa wa 然后我改 改 改 然后继续 wa wa wa我wa了13次 最后被大佬看出这个错误来,虽然我现在也不知道为什么。。。。但是这个地方是真滴难受!
在这里插入图片描述

  • AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=2e5+10;
struct node{
	double left;
	double right; 
}a[maxn];
int n,length,width;
bool cmp1(struct node x,struct node y)
{
	return x.right>y.right;
}
int main()
{
	while(cin>>n>>length>>width)
	{
		int cnt=0;
		for(int i=0;i<n;i++)
		{
			double pos,r;
			cin>>pos>>r;
			if(r*2<=width)
				continue;
			double t;
			t=sqrt((double)(2*r*2*r)-width*width)/2;
			a[cnt].left=(double)pos-t;
			a[cnt].right=double(pos)+t;
			cnt++;
		}
		sort(a,a+cnt,cmp1);

		
		int num=0;
		double left=0.0,right=(double)length;
		while(left<right)
		{
			int i=0;
		//	cout<<"s"<<endl;
			for( i=0;i<cnt;i++)
			{
				if(a[i].left<=left&&a[i].right>left)
				{
					num++;
					left=a[i].right;//更新区间
					break;
				}
			}
			if(i==cnt)///找了一圈没有合适的
			{
				break;
			}
		}
		if(left<right)
			cout<<"-1"<<endl;
		else
			cout<<num<<endl;
	}
}
/*
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
*/

猜你喜欢

转载自blog.csdn.net/weixin_43179892/article/details/84863990