Radar Installation贪心详解

  • 假定海岸线是无限长的直线。陆地位于海岸线的一侧,海洋位于另一侧。每个小岛是位于海洋中的一个点。对于任何一个雷达的安装
    (均位于海岸线上),只能覆盖 d 距离,因此海洋中的小岛被雷达安装所覆盖的条件是两者间的距离不超过 d 。

    我们使用卡笛尔坐标系,将海岸线定义为 x 轴。海洋的一侧位于 x
    轴上方,陆地的一侧位于下方。给定海洋中每个小岛的位置,并给定雷达安装的覆盖距离,您的任务是写一个程序,找出雷达安装的最少数量,使得所有的小岛都被覆盖。注意:小岛的位置以它的
    x-y 坐标表示。

  • 输入:输入由多个测试用例组成。每个测试用例的第一行,包含了两个整数 n (1<=n<=1000) 和 d,其中 n 是海洋中小岛的数目,d
    是雷达安装的覆盖距离。接下来是 n 行,每行包含了两个整数,表示每个小岛的坐标。每组测试用例之间,以一个空行间隔。输入终止于包含两个 0 的一行。

  • 输出:对于每个测试用例,输出一行,包括测试用例的编号,以及雷达安装所需的最小数量。"-1" 个安装,表示该测试用例无解决方案。

  • 示例输入

    3 2 1 2
    -3 1 2 1     
    1 2 0 2        
    0 0
    
  • 示例输出

    Case 1: 2 
    Case 2: 1
    
  • 分析:以小岛为圆心,以雷达的范围为半径,作圆。如果这个圆交X轴一个线段或者一个点,则能找到安置雷达的地方覆盖这个点,用勾股定理将每一个小岛都变为X轴上的一个选段,取最少的点覆盖所有的线段,所取点数就是雷达数。

代码示例1:

#include <cstdio>
#include <map>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <functional>
using namespace std; 
multimap<double,double,greater<double> > m;
int main()
{
	int n,d,s=1;
	while(cin>>n>>d)
	{
		if (!n)
            break;
		int cou=0;
		int x,y;
		for(int i=0;i<n;i++)
		{
			cin>>x>>y;
			double b=(double)d*d-y*y;
			if(b>=0&&d>=0)
			{
				b=sqrt(b);
				m.insert(pair<double,double>(x-b,x+b));
			}
			else
			{
				cou=-1;
			}			
		}			
		if (cou!=-1) {
            cou = 1;
            double c=m.begin()->first;			
			for (auto it = m.begin();it!=m.end();it++) {
                if (it->second < c) {
                    c=it->first;
                    ++cou;
                }
            }
        }
		cout<<"Case "<<s++<<": "<<cou<<endl;	
		m.clear();		
	}
}

改变multimap 的默认排序,使其按照Key 从大到小排序。

可分析知:从最后一个小岛线段的左端放置雷达,可以覆盖最多的线段,贪心算法。
所以每次都放置在前一个雷达不能覆盖的一个小岛线段的左端。

double c=m.begin()->first;			
for (auto it = m.begin();it!=m.end();it++) {
      if (it->second < c) {
      		c=it->first;
      		++cou;
       }
}
  • 注释:两个示例,两种不同的比较方式,一种从左往右,一种从右往左。

代码示例2:
用数组来做。

#include<iostream>
#include<algorithm>
using namespace std;
struct Range
{
    double l;
    double r;
}range[1001];
bool cmp(Range a, Range b)
{
    return a.r < b.r;
}
int main()
{
    int n, d, cnt = 0;
    double x, y;
    while (1) {
        cin >> n >> d;
        if (!n)
            break;
        bool flag = d >= 0;
        for (int i = 0; i < n; ++i) {
            cin >> x >> y;
            flag = flag && y <= d;
            if (flag) {
                range[i].l = x - sqrt(d * d - y * y);
                range[i].r = x + sqrt(d * d - y * y);
            }
        }
        sort(range, range + n, cmp);
        int rst = -1;
        if (flag) {
            rst = 1;
            double maxr = range[0].r; 
            for (int i = 1; i < n; ++i) {
                if (range[i].l > maxr) {
                    maxr = range[i].r;
                    ++rst;
                }
            }
        }
        cout << "Case " << ++cnt << ": " << rst << endl;
    }
    system("pause");
}

排序提示:第二个示例中,当右端点相同时,左端点顺序随意,无需管左端点的排序。

自己的分析,若觉得有错,欢迎批评。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值