借鉴于:https://blog.csdn.net/lyy289065406/article/details/6642599+小修改
题意分析:
给定一个直角坐标系,定义x轴为海岸线,海岸线上方是海,下方是陆地.
在海域零星分布一些海岛, 需要要在海岸线上安装若干个雷达覆盖这些海岛,
每个雷达的覆盖半径都是相同且固定的.
现在给定所有海岛的坐标(x,y), 以及雷达的覆盖半径d,
问可以覆盖所有海岛的最小雷达数.
?错误?思路:
每个雷达画圆。从三点定圆的思路找:先找出相同x坐标下的y-max,随后对于每个y-max按照从左往右的顺序找出满足要求的最远的雷达位置。但是,由于没有考虑到两个雷达之间的衔接以及y-max点不一定在圆的边界,导致错误。
正确思路:
每个点画圆。然后在x轴上有交点(如果没有代表不存在解)。每一个截距区间为能够探测到岛的雷达的范围;然后找尽可能多的重复;由此,将x-y坐标变成x-区间问题。
转化为-->如何找到尽可能少的点,使得每一个独立区间内都有一个点。
方法:如果两个区间有重合,选择重合的小区间作为点出现的可能区间;如果没有重合,则重新选择一个新的点。
从左往右开始查找,那么把点出现区间的最右端作为点的真实位置;如果有重合,点数量不增加,但是位置可能发生改变(在重合区间的最右端);如果不重合,点数量增加,位置也改变。
错误分析:
if (intervals[i].left <= pos)
pos = min(intervals[i].right, pos);//internal or others
else
{
++ans;
pos = intervals[i].right;
}
这里min应该取pos(原来的点位置),而不是intervals[i-1].right
double r;
const double r_2 = d*d;
for (int i = 0; i < n; ++i)
{
cin >> x >> y;
if (y > d)
{
ans = false;
}
r = sqrt(r_2 - y * y);
好几处的double转换应该注意。不然会错误。
标准代码:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
int n, d;
struct interval
{
double left, right;
} intervals[1005];
bool cmp(interval a, interval b)
{
return a.left <= b.left;// have to be
}
void print(){
cout << '\n';
for(int i = 0 ; i < n; ++i){
cout << intervals[i].left << ' ' << intervals[i].right << '\n';
}
cout << '\n';
}
int f()
{
sort(intervals, intervals + n, cmp);
// print();
int ans = 1;
double pos = intervals[0].right;
for (int i = 1; i < n; ++i)
{
if (intervals[i].left <= pos)
pos = min(intervals[i].right, pos);//internal or others
else
{
++ans;
pos = intervals[i].right;
}
}
return ans;
}
int main()
{
int cnt = 0;
while (1)
{
cin >> n >> d;
if (n == 0 || d == 0)
break;
bool ans = true;
int x, y;
double r;
const double r_2 = d*d;
for (int i = 0; i < n; ++i)
{
cin >> x >> y;
if (y > d)
{
ans = false;
}
r = sqrt(r_2 - y * y);
intervals[i].left = x - r;
intervals[i].right = x + r;
}
cnt++;
cout << "Case " << cnt << ": " << (ans ? f() : -1) << '\n' ;
}
return 0;
}