-
假定海岸线是无限长的直线。陆地位于海岸线的一侧,海洋位于另一侧。每个小岛是位于海洋中的一个点。对于任何一个雷达的安装
(均位于海岸线上),只能覆盖 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");
}
排序提示:第二个示例中,当右端点相同时,左端点顺序随意,无需管左端点的排序。
自己的分析,若觉得有错,欢迎批评。