题意:如今我们位于沿海地区,需要安装大炮,使得火力可以覆盖整个区域。海岸线可以视为是无限长的直线。陆地位于海岸线的一侧,海洋位于另一侧。海洋里有若干个岛屿,每个小岛可以视为海洋中的一个点。我们需要在海岸线上安装大炮,每个大炮智能覆盖距离d,因此海洋中的小岛被大炮安装所覆盖的条件是两者间的距离不超过 d 。 我们将海岸线视为 x 轴。海洋的一侧位于 x 轴上方,陆地的一侧位于下方。给定海洋中每个小岛的位置(以xy坐标给出),并给定大炮的覆盖距离,你需要写程序,找出安装大炮的最少数量,使得所有的小岛都被覆盖。
题解:我们先将所有的岛屿视为圆心,以半径d做圆,如果最远距离大于d的,直接视为无法完全覆盖,输出-1;
如果全部可以覆盖,则可以认为x轴对于圆的割线就是满足题意的炮台位置,此时本题就转化为了贪心问题中的基操——区间选点问题
区间选点问题的题型:n个区间[ai,bi],在数轴上选取尽可能少的点,能保证每段区间上都能有一个点。
区间选点的贪心策略:右端点从小到大排序,如果右端点相同则左端点从大到小排序
贪心过程:标记第一个右端点为r,不断向后与下一段的左端点开始比较,如果下一段的左端点大于r,则更新r,否则一直向后找
#include<stdio.h> #include<algorithm> #include<iostream> #include<math.h> using namespace std; struct node { double x; double y; }island[1050]; struct point { double l; double r; }p[1050]; bool cmp(point a, point b) { if (a.r == b.r) return a.l > b.l; return a.r < b.r; } int main(void) { ios::sync_with_stdio(false); int n; double d; int k = 1; while (cin >> n >> d) { if (n == 0 && d == 0) break; int flag = 0; for (int i = 0; i < n; i++)//n是海洋中小岛的数目,d是大炮可以覆盖的距离 { cin >> island[i].x >> island[i].y; if (island[i].y > d || island[i].y < 0) flag = 1; else { p[i].l = double(island[i].x - sqrt(d * d - island[i].y * island[i].y)); p[i].r = double(island[i].x + sqrt(d * d - island[i].y * island[i].y)); } } if (flag == 1) { cout << "Case " << k << ": " << "-1" << endl; k++; } else { sort(p, p + n, cmp); double r = p[0].r; int count = 1; for (int i = 1; i < n; i++) { if (p[i].l <= r) continue; else { count++; r = p[i].r; } } cout << "Case " << k << ": " << count << endl; k++; } } return 0; }