喷水装置问题 贪心算法

长L米,宽W米的草坪里装有n个浇灌喷头。每个喷头都装在草坪中心线上(离两边各W/2米)。我们知道每个喷头的位置(离草坪中心线左端的距离),以及它能覆盖到的浇灌范围。
请问:如果要同时浇灌整块草坪,最少需要打开多少个喷头?

输入格式:
输入包含若干组测试数据。

第一行一个整数T表示数据组数。

每组数据的第一行是整数n、L和W的值,其中n≤10 000。

接下来的n行,每行包含两个整数,给出一个喷头的位置和浇灌半径。

如下图所示的示意图是样例输入的第一组数据所描述的情况。
在这里插入图片描述
输出格式:
对每组测试数据输出一个数字,表示要浇灌整块草坪所需喷头数目的最小值。如果所有喷头都打开还不能浇灌整块草坪,则输出-1。

输入样例:

3
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

输出样例:

6
2
-1

数据范围与提示:
对于100%的数据,n≤15000。
完整代码及理解:
下图中蓝色框出的部分才是喷水的覆盖面积范围
在这里插入图片描述

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int t,n,l;//组数,喷头数,长度
int s;//喷头位置 
double w,r;//草坪宽度,喷头半径
double maxn;//临时变量
int main()
{
    
    
	vector< pair<double,double> >vec;
	pair<double,double> p;
	cin>>t;//输入总组数
	while(t--)//t--不等于0时
	{
    
    
       cin>>n>>l>>w;//输入喷头数,草坪长、宽
	   vec.clear();//确保容器vec为空
	   for(int i=0;i<n;i++)
	   {
    
    
		   cin>>s>>r;//输入喷头位置、半径
		   if(r<w/2)
			   continue;//如果半径小于宽度的一半,则一定不会覆盖草坪,获取下一个喷头数据
		   r=sqrt(r*r-(w/2*w/2));//勾股定理逆用,
           p=make_pair(s-r,s+r);//求区间
		   vec.push_back(p);//尾部插入区间
	   }
	   sort(vec.begin(),vec.end());//升序
	   int k=0;//记录已遍历到的喷头数
	   double now=0;//记录覆盖到的位置
	   int ans=0;//记录选用的的喷头数
	   int flag=1;//标记是否还能覆盖
	   int len=vec.size();//容器大小
	   while(k<len)
	   {
    
    
		   if(now<vec[k].first)
		   {
    
    flag=0;
		   break;}//前面覆盖到的位置与当前可覆盖区间不相交,即存在不覆盖的情况
		   if(now>=l)break;//覆盖已完成
		   maxn=-1;
		   while(now>=vec[k].first&&k<len)//当下一个区间可覆盖,尽可能选覆盖区间最大的
		   {
    
    
			   maxn=max(maxn,vec[k].second);
			   k++;//记录已遍历的喷头数
		   }
		   now=maxn;
		   ans++;//每换一个区间,选用的喷头数加一
	   }
       if(flag==1)
		   cout<<ans<<endl;
	   else 
		   cout<<"-1"<<endl;
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_51063573/article/details/110942077