喷水装置(二) 区间长度贪心

本文介绍了一种算法,用于解决如何用最少数量的喷水装置将一块草坪完全润湿的问题。通过计算每个喷水装置的有效润湿范围,并采用区间覆盖的方法找到最佳组合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述
有一块草坪,横向长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


分析:

告诉你喷水的位置和喷射的半径,你可以求出能覆盖矩形草坪在水平方向上的长度,即知道每个喷水的左右端点,剩下的就是求在固定区间内问最少多少个小区间能够覆盖





#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <string>
using namespace std;
double len(double a,double b)
{
    return sqrt(a*a-b*b);
}
int cmp(pair<double,double>a,pair<double,double>b)
{
	return a.first < b.first;
}
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
    	int n,w,h;
    	cin >> n >> w >> h;
    	vector<pair<double,double> >v;
    	for(int i = 0;i < n;i++)
    	{
    		int x,r;
    		cin >> x >> r;
    		double l = len(r,h/2.0);
    		if(l > h/2.0)
    		{
    			pair<double,double>p;
    		    p.first = x-l;
    		    p.second = x+l;
    		    v.push_back(p);
    		}
    	}
    	sort(v.begin(),v.end(),cmp);
    	int cnt = 0;
    	double right = 0;
        while(right < w)
        {
        	double m = 0.0;
        	///求尽可能在已知区间上向右扩展的最大的右端点,使得尽可能使用较少的喷水器就能全部覆盖
        	for(int i = 0;i < v.size()&&v[i].first <= right;i++)
        	{
                if(v[i].second - right > m)m = v[i].second - right;
        	}
        	if(m)
        	{
        		cnt++;
        		right+=m;
        	}
        	else
        		break;///如果扩展不动了,那就说明已经扩展完成了
        }
        if(right < w)
        	cout << 0 << endl;
        else
        cout << cnt << endl;
    }
	return 0;
}











#include <iostream>  
#include <cstdio>  
#include <algorithm>  
#include <cstring>  
#include <cmath>  
#include <vector>  
#include <set>  
#include <map>  
#include <stack>  
#include <string>  
using namespace std;  
double len(double a,double b)  
{  
    return sqrt(a*a-b*b);  
}  
int cmp(pair<double,double>a,pair<double,double>b)  
{  
    return a.first < b.first;  
}  
int main()  
{  
    int t;  
    //ios::sync_with_stdio(false);
    cin >> t;  
    while(t--)  
    {  
        int n,w,h;  
        //cin >> n >> w >> h;  
        scanf("%d%d%d",&n,&w,&h);
        vector<pair<double,double> >v;  
        for(int i = 0;i < n;i++)  
        {  
            int x,r;  
            //cin >> x >> r;  
            scanf("%d%d",&x,&r);
            double l = len(r,h/2.0);  
            if(l > h/2.0)  
            {  
                pair<double,double>p;  
                p.first = x-l;  
                p.second = x+l;  
                v.push_back(p);  
            }  
        }  
        sort(v.begin(),v.end(),cmp);  
        int cnt = 0;  
        double right = 0;
        int top = 0;  
        while(right < w)  
        {  
            double be = right+0.000001;///每次加上0.000001,俩区间有断点,就能区分
            for(int i = top;i < v.size();i++)
            {
            	if(v[i].first <= be&&v[i].second >= be)
            	{
            		right = v[i].second > right ? v[i].second:right;
            	}
            	else if(v[i].first > be)
            	{
            		top = i;
            		break;
            	}
            }
            if(be > right) break;
            else cnt++;
        }  
        if(right < w)  
            //cout << 0 << endl;  
            printf("0\n");
        else  
        //cout << cnt << endl;  
        	printf("%d\n",cnt);
    }  
    return 0;  
}













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值