翻译过来就是:
解题思路:
把这个二维的问题转化为转化为一维的问题。如上图所示,只需要雷达安装在这个区间中的话,雷达就能够覆盖到上面的岛屿。现在这个问题又变成区间调度问题了。但是还有一个问题就是在这个区间中说明位置上放置雷达呢?这个区间可是有无数个点,枚举肯定不可能。解决方向如下:
说实话作为一个小白而言上面这个真的不容易看懂,但是可以作为经验来积累,以每一个区间的起点进行放置雷达。
首先我发现了一件事就是贪心法好像很多都有编号这个步骤。这个其实根据这个区间来理解其实就不会很复杂了第一个雷达放在第三个区间的起点。第二个雷达放在倒数第二个。这样依次类推。
后面贪心法的证明我不爱写了,我觉得这个替换法难度还是偏大,我后面自己酝酿一下再来写吧。
后面是代码实现。
#include <cstdio> #include <algorithm> #include <cmath> using namespace std; struct Island { double x, y; double max, min; }island[1000]; /* 贪心思想,很多情况下是考虑极值,本题也正是先将每个island的区间求出来,什么是区间? * 其实就是在海岸边(也就是x轴上)的范围内任何一个位置放置一个雷达都能够覆盖到这个岛,就称 * 这个岛的区间! */ /** * 比较函数。 选用什么排序是关键,一开始错误地选择了横坐标x排序,结果数据基本对的上, * 仔细一想其实应该是要用每个island的左右闭区间端点排序才对。 第二次选择的时候,又 * 错误地选择了右区间端点,其实应该选择左端点,从我下面的贪心的具体算法可以看出,其实 * 我是用min(左端点)去确保从右往左的所有island能够covered。 */ int cmp(const Island &a, const Island &b) { return a.min < b.min; } int main() { int n, cases = 1, count; char isOk; double d; while(scanf("%d%lf", &n, &d), n) { isOk = 0; count = 1; int i; for(i = 0; i < n; i ++) { scanf("%lf%lf", &island[i].x, &island[i].y); if(island[i].y > d || island[i].y < 0) { isOk = 1; } island[i].max = island[i].x + sqrt(d * d - island[i].y * island[i].y); island[i].min = island[i].x - sqrt(d * d - island[i].y * island[i].y); } if(isOk == 1) { printf("Case %d: -1\n", cases); cases ++; continue; } sort(island, island + n, cmp); double min; int j = n - 1; /* 关键是 当 island[j].max < min 的时候,是指从右往左一个个island扫描的时候,保证每个都能覆盖到,而且是用最少的雷达数。 */ for(i = j; i >= 0; i --, i = j) { min = island[i].min; for(j = i - 1; j >= 0; j --) { if(island[j].max < min) { count ++; break; } } } printf("Case %d: %d\n", cases, count); cases ++; } return 0; }