POJ3069 -- Saruman's Army
题意:
直线上有N个点。 点i的位置是Xi。从这N个点中选择若干个,给它们加上标记。 对每一个点,其距离为R以内的区域里必须有带有标记的点(自己本身带有标记的点, 可以认为与其距离为 0 的地方有一个带有标记的点)。 在满足这个条件的情况下, 希望能为尽可能少的点添加标记。 请问至少要有多少点被加上标记?
Ps:多组输入,直到N / R = -1时候结束
输入
0 3
10 20 20
10 7
70 30 1 7 15 20 50
-1 -1
输出
2
4
解析:区间类型的贪心题。开始将最左边的点设为未被覆盖的点bg,向右寻找至第一个小于或等于bg + R的点,此时可以将该点标记为p,接着p其实也覆盖了p + R,那找到第一个大于p + R的点作为下一个最左边未被覆盖的点,依次下去。下面大概草草的画了一个图作为理解。

AC代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long LL;
const int num = 1005;
int r, n, p, res;
int a[num];
int main()
{
ios::sync_with_stdio(false);
while(cin >> r >> n && (r != -1 || n != -1))
{
memset(a, 0, sizeof(a));
res = 0, p = 0;
for(int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + n + 1);
int i = 1; //此时运动到第i个点
while(i <= n)
{
int bg = a[i]; //表示当前未覆盖的最左边位置
for(int j = i + 1; ; j++) //找到bg最右边且小于r的点进行标记
{
if(a[j] - bg > r)
{
p = a[j-1]; //将标记点记录
i = j; //更新当前位置
res++; //标记点数量增加
break;
}
}
for(int j = i; ; j++) //标记点还能覆盖其右边小于r的位置
{
if(a[j] - p > r) //当该点大于r时, 重新作为当前未覆盖的最左边位置
{
i = j; //更新当前位置
break;
}
}
}
cout << res << endl;
}
return 0;
}

浙公网安备 33010602011771号