假设海岸是一条无限长的直线,陆地位于海岸的一侧,海洋位于另外一侧。
每个小岛都位于海洋一侧的某个点上。
雷达装置均位于海岸线上,且雷达的监测范围为 dd,当小岛与某雷达的距离不超过 dd 时,该小岛可以被雷达覆盖。
我们使用笛卡尔坐标系,定义海岸线为 xx 轴,海的一侧在 xx 轴上方,陆地一侧在 xx 轴下方。
现在给出每个小岛的具体坐标以及雷达的检测范围,请你求出能够使所有小岛都被雷达覆盖所需的最小雷达数目。
输入格式
第一行输入两个整数 nn 和 dd,分别代表小岛数目和雷达检测范围。
接下来 nn 行,每行输入两个整数,分别代表小岛的 x,yx,y 轴坐标。
同一行数据之间用空格隔开。
输出格式
输出一个整数,代表所需的最小雷达数目,若没有解决方案则所需数目输出 −1−1。
数据范围
1≤n≤10001≤n≤1000,
1≤d≤2001≤d≤200,
−1000≤x,y≤1000−1000≤x,y≤1000
输入样例:
3 2
1 2
-3 1
2 1
输出样例:
2
首先遇到这道题的第一个感受,就是如果以雷达站为思考对象,发现无从下手,根据正难则反的思想,我们来想一想小岛,如果思考雷达站是看看雷达站可以覆盖几个岛,而雷达站位置不确定就很难下手,那么思考小岛,确定每个岛对应的可被探测区间,让位置不定的雷达站可以在区间里移动,这就是这道题的整体思路
然后利用勾股定理计算一下每个小岛对应的区间(x+-=sqrt(r*r-y*y)),这个比较简单
然后是我的三种排序(按小岛x坐标排序,按小岛范围左顶点排序,按小岛范围右顶点排序)
三种都分析一下所有情况
首先,为了尽可能容纳更多的岛屿,第一个基站选择在三种排序的第一个的区间右顶点
此时,在更新区间时有三种情况:
第一种:新区间的左顶点在上一个雷达站位置的右侧,即上一个雷达站无法探测到下一个区间对应的岛,这时候三种区间的处理方法是一样的,雷达站次数加一,且将雷达站设置到新区间的右侧顶点
第二种:新区间的左顶点和上一个雷达站位置重合,说明雷达刚好可以照射到新区间对应的小岛,此时直接continue即可
第三种:本题大坑,新区间的左顶点在上一个雷达站位置的左侧,此时右分为两种情况,一种是上一个区间部分包含新区间,一种是上一个区间全部包含新区间,前一种情况和第二种基本类似,后一种可能会出现问题,比如两个区间(0,5)和(3,4)(由于岛有y轴所以区间大小不定),如果是按小岛范围的右顶点排序,则顺序是(3,4),雷达站位置4,到(0,5)雷达站数目加一且变为位置5不会有问题,但是如果是按小岛x轴坐标或者小岛范围左顶点排序,则会出现一个问题,首先是(0,5),雷达站位置为5,然后是(3,4),会发现一个问题,(3,4)区间根本不会被探测到,所以,在出现此类全包含的问题时,我们要把雷达站位置更新为被包含区间的最右侧顶点
解析如上,分别复制以上三种排序对应ac代码
/*#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
int main()
{
double n, r;
cin >> n >> r;
vector<double>x;
vector<double>y;
for (double i = 0; i < n; i++)
{
double a, b;
cin >> a >> b;
x.push_back(a);
y.push_back(b);
}
for (double i = 0; i < n; i++)
{
for (double j = 0; j < i; j++)
{
if (x[i] < x[j])
{
swap(x[i], x[j]);
swap(y[i], y[j]);
}
}
}
vector<pair<double, double>>points;
for (double i = 0; i < n; i++)
{
double a = x[i];
double b = y[i];
if (r * r - b * b < 0)
{
cout << -1;
return 0;
}
double c = sqrt(r * r - b * b);
double x1 = a - c;
double x2 = a + c;
points.push_back({ x1,x2 });
}
//for (auto p : points)
//{
// cout << p.first << " " << p.second << endl;
//}
int count = 1;
vector<int>sign(0, n);
double origin = points[0].second;
for (int i = 1; i < n; i++)
{
if (points[i].first == origin)
{
continue;
}
else if (points[i].first > origin)
{
count++;
origin = points[i].second;
}
else
{
origin = min(origin, points[i].first);
}
}
cout << count;
return 0;
}*/
/*#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
int main()
{
double n, r;
cin >> n >> r;
vector<double>x;
vector<double>y;
for (double i = 0; i < n; i++)
{
double a, b;
cin >> a >> b;
x.push_back(a);
y.push_back(b);
}
vector<pair<double, double>>points;
for (int i = 0; i < n; i++)
{
double x1 = x[i];
double y1 = y[i];
double d = r * r - y1 * y1;
if (d < 0)
{
cout << -1;
return 0;
}
double d1 = sqrt(d);
points.push_back({ x1 - d1,x1 + d1 });
}
sort(points.begin(), points.end());
int count = 1;
double origin = points[0].second;
for (int i = 1; i < n; i++)
{
if (points[i].first > origin)
{
count++;
origin = points[i].second;
}
else
{
origin = min(origin, points[i].second);
}
}
cout << count;
return 0;
}*/
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
int main()
{
double n, r;
cin >> n >> r;
vector<double>x;
vector<double>y;
for (double i = 0; i < n; i++)
{
double a, b;
cin >> a >> b;
x.push_back(a);
y.push_back(b);
}
vector<pair<double, double>>points;
for (int i = 0; i < n; i++)
{
double x1 = x[i];
double y1 = y[i];
double d = r * r - y1 * y1;
if (d < 0)
{
cout << -1;
return 0;
}
double d1 = sqrt(d);
points.push_back({ x1 - d1,x1 + d1 });
}
sort(points.begin(), points.end(), [](const auto& a, const auto& b) {
return a.second < b.second;
});
int count = 1;
double origin = points[0].second;
for (int i = 1; i < n; i++)
{
if (points[i].first > origin)
{
count++;
origin = points[i].second;
}
}
cout << count;
return 0;
}