【问题描述】
萨鲁曼的大军正行进在一条笔直的道路上,由于是在夜晚行军,路上的石头严重地影响了行军速度。于是萨鲁曼决定预先在道路上安装一些路灯,以便士兵们能清楚地看到所有石头。
萨鲁曼给出n块石头的位置Xi,现在需要在这些位置中选择若干个位置设置路灯。每盏路灯的照亮范围为R,即若你在Xi处设置了一盏路灯,则在[Xi-R,Xi+R]的范围内都会被照亮。
现在请你计算最少设置多少盏路灯,就能把所有石头照亮。
【输入格式】
含多组测试数据,每组数据占两行:第一行为 R 和 n ,第二行包含n个整数,表示Xi。
【输出格式】
每组数据输出一行一个整数,表示最少的路灯数量。
【输入样例】
0 3
10 20 20
10 7
70 30 1 7 15 20 50
-1 -1
【输出样例】
2
4
【样例解释】
第一组数据,两盏路灯分别设置在10和20的位置
第二组数据,在位置7处设置一盏路灯(可以照亮1,7,15处的石头),在位置20处设置一盏路灯(可以照亮20,30l处的石头),在位置50处设置一盏路灯(可以照亮50处的石头),在位置70处设置一盏路灯(可以照亮70处的石头)。
【数据范围】
1<=n<=1000 , 0<=R,Xi<=10^9
最多不超过1000组数据
【思路梳理】
简单题,所谓石头可以想象成一条坐标轴上的点,安装的路灯就是坐标轴上的区间,那么这个题就是要求在坐标轴上贪心地选择一些给定的区间来覆盖所有的点,并求出所选的区间个数,依然可以用上面提到的“感染法”,只是我们不需要对区间进行标记。
以第i个点进行考虑:首先考虑在第j个石头安装路灯,那么在能够覆盖到i的前提下j应该尽可能的远。显然这个时候应该在第j块石头处安装路灯而非第i块石头处(因为j的右边仍然有石头等待被覆盖),那么继续标记第j块石头右边能够覆盖到的石头就可以。
【Cpp代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1005
using namespace std;
int stone_num,range;
struct info { bool vis; int pos,left,right; }stone[maxn];
bool cmp(info a,info b) { return a.pos<b.pos; }
void TASK()
{
int j,ans=0;
for(int i=1;i<=stone_num;i++)if(!stone[i].vis)
{
for(j=i;j<=stone_num;j++)//贪心地确定路灯的位置,在路灯j能够覆盖到石头i前提下使得路灯j尽可能的远
{
stone[j].vis=true;//寻找路灯安装位置的过程中,这些stone全部标记掉
if(stone[j+1].pos>stone[i].right)
{
i=j;//直接i移动到第j块石头处,进行路灯安装
break;
}
}
for(int j=i;j<=stone_num;j++)if(stone[j].pos<=stone[i].right)
stone[j].vis=true;
//确定路灯右侧能够照亮的stone
ans++;
}
printf("%d\n",ans);
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&range,&stone_num)==2)
{
memset(stone,0,sizeof(stone));
if(range==-1 && stone_num==-1) break;
for(int i=1;i<=stone_num;i++)
{
scanf("%d",&stone[i].pos);
stone[i].vis=false;
stone[i].left=stone[i].pos-range;
stone[i].right=stone[i].pos+range;
}
sort(stone+1,stone+1+stone_num,cmp);
TASK();
}
return 0;
}