题意:在一条直线上,有n个点。从这n个点中选择若干个,给他们加上标记。对于每一个点,其距离为R以内的区域里必须有一个被标记的点。问至少要有多少点被加上标记。
题解:
题解:我们从最左边的开始考虑。对于这个点,到距其R以内的区域必须要有带有标记的点。带有标记的点一定在其右侧(包含这个点本身)。给从最左边开始,距离为R以内的最远的点加上标记,尽可能的覆盖更靠右边的点。对于添加了标记的点右侧相距超过R的下一个点,采用同样的方法找到最右侧R距离以内最远的点添加标记。在所有点都被覆盖之前不断重复这一过程。
贪心算法
#include<stdio.h>
void sort(int *a, int left, int right)
{
if(left>=right)/*如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了*/
{
return ;
}
int i=left;
int j=right;
int key=a[left];
while(i<j) /*控制在当组内寻找一遍*/
{
while(i<j&&key<=a[j])
/*而寻找结束的条件就是,1,找到一个小于或者大于key的数(大于或小于取决于你想升
序还是降序)2,没有符合条件1的,并且i与j的大小没有反转*/
{
j--;/*向前寻找*/
}
a[i]=a[j];
/*找到一个这样的数后就把它赋给前面的被拿走的i的值(如果第一次循环且key是
a[left],那么就是给key)*/
while(i<j&&key>=a[i])
/*这是i在当组内向前寻找,同上,不过注意与key的大小关系停止循环和上面相反,
因为排序思想是把数往两边扔,所以左右两边的数大小与key的关系相反*/
{
i++;
}
a[j]=a[i];
}
a[i]=key;/*当在当组内找完一遍以后就把中间数key回归*/
sort(a,left,i-1);/*最后用同样的方式对分出来的左边的小组进行同上的做法*/
sort(a,i+1,right);/*用同样的方式对分出来的右边的小组进行同上的做法*/
/*当然最后可能会出现很多分左右,直到每一组的i = j 为止*/
}
int a[1000];
int main()
{
int r,n;
while(scanf("%d%d",&r,&n)!=EOF)
{
if(r==-1&&n==-1)
break;
int sum=0,j=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
sort(a,0,n-1);
while(j<n)
{
int sts=a[j++];//先赋值
while(j<n&&a[j]<=sts+r)//覆盖范围内,左半部分
j++;
int stn=a[j-1];
while(j<n&&a[j]<=stn+r)//右半部分
j++;
sum++;
}
printf("%d\n",sum);
}
}