POJ 3069 Saruman's Army(贪心+区间覆盖)
原题地址
http://poj.org/problem?id=3069
题意:X轴上有n个点Xi,雷达必须被放置在点上,且能探测与其距离为R内的所有点,求能覆盖所有点的最少雷达数。
解题思路
这题属于贪心算法的题目,很明显也是区间覆盖问题。
我也是愚蠢到极致了,才会想着记录每个点的R范围内的邻居数,对邻居数降序排,在邻居数最多的点上放雷达。浪费了一个半小时,数组套数组,还是WA,debug失败只能参考大神的博客。
看了大神的解释,醒悟到这题与上一篇POJ 2586应该是同一种思路,即让特殊点的影响尽量向后面辐射,来减少之后摆放标记点的数目。
贴一下大神的博客:POJ3069 POJ2586 解题报告(异曲同工的贪心算法)
总结一下外层while循环里执行的任务:
- 从左到右看,选择需要被新雷达覆盖的最左点xi
- 找到[xi, xi+R]内最靠右的点,放置新的雷达
- 找到新雷达Xj辐射范围[xj, xj+R]内的最靠右的点,其下一个点就是下一个雷达要覆盖的最左点
AC代码
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a[1001];
int R,n;
while (cin >> R >> n)
{
if (R == -1 && n == -1) break;
for (int i = 0; i<n; ++i)
cin >> a[i];
sort(a, a+n); //按横坐标升序
int index = 0, cnt = 0;
while (index < n) //判断时index指向旧雷达探测不到的最左点
{
//找到当前点右侧R范围内最靠右的点,即雷达摆放点
int range = a[index] + R;
while (index < n && a[index] <= range)
index++; //跳出时index指向雷达摆放点的下一个
cnt++; //在index-1位置放新雷达
//跳出新雷达的右界,即找到下一个雷达探测的最左点
range = a[index-1]+R; //以index-1为圆心的右侧R范围
while (index < n && a[index] <= range)
index++;
}
cout << cnt << endl;
}
return 0;
}
内存占用: 232K 耗时:63ms
算法复杂度:O(n2)