POJ - 3069

题目

一个游戏:在一条直线上有N个糖果。第i个糖果的位置是X[i]。从这N个糖果中选择若干个,把他们标记起来。对于每一个糖果,在和它本身相距为R的区域内必须要有标记的糖果(本身带有标记的糖果,就可以认为和它相距为0的地方有一个糖果被标记)。在满足这个条件的情况,最后如果有a个糖果被标记,编写程序使a最小化。

输入

输入的测试文件将包含多个样例。 每个测试样例第一行有两个数据,整数R(其中0≤R≤1000)和整数N(其中1≤N≤1000)。 下一行包含N个整数,指示每个糖果的位置X[1],…,X[N](其中0≤X[i]≤1000)。当R == N== -1时,输入结束。

输出

对于每组输入数据,输出一个数,代表a的最小值。

样例

输入样例1

0 3
10 20 20
10 7
70 30 1 7 15 20 50
-1 -1

输出样例1

2
4

分析

入门级贪心问题,思路其实不难,最开始想的和书上差不多只是方向反了,直接从point+r开始向回找,这个思路其实也行,但代码实现有问题

本题既然是统计标记多少个点,就从第一个点开始找,找到要标记的第一个点之后再在这个点往后最大r的位置之内标记新一个点再对这个点往后找r,如此往复……

代码实现的问题在于习惯了用for之后总是不会用while...这个真的有点伤

还有测试数据会出现有多个点相同的情况,最开始以为需要把相同的点去掉只留一个点(淦);对此我的方法是sort之后套两层循环,找到之后跳过这个点,把后面的用第二层for接上来,然后n自减一次。在网上看到了另一种代码实现:基于打表实现,直接在输入的时候解决:

int vis[2000];
memset(vis, 0, sizeof(vis));//标记这些点为未访问状态
for (int i=0; i<n; i++){
	int num;
	scanf("%d", &num);//读入当前数
	    if (vis[num] == 0){//如果未被访问过
			 vis[num]++;  //先标记为已访问过
			 a[j++] = num;//再将这个数存入数组
		 }
}
//这样就不用实现n的自减了(可以直接把j的值当做自减过得n用)

然而残忍的是,费半天劲实现的去重居然没啥用,因为相同的点在这个代码中不会被统计多次

如果出现相同的点,最多只需要标记一个即可

while(i<n){
//假设现在走到了相同的点
				int sp=inp[i++];//sp是i(相同点的第一个),此时i自增,指向的是相同点的第二个
				while(i<n&&inp[i]<=sp+r){//如果i<n(防数组越界)且这个点在r范围内,i就继续自增
					i++;
				}
				sp=inp[i-1];
				while(i<n&&inp[i]<=sp+r){//原理同上,只要这个点还在r的范围内就自增
					i++;
				}
				ans++;//在这里计数,所以上面有几个相同的点都不影响最后的计数
}

咿~~还是写之前一直囿于for循环,怎么写都会导致相同点会自增的原因导致的,不过加了也不会TLE就是了

代码

#include <cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

int main(){
	int r,n;
	while(scanf("%d %d",&r,&n)!=EOF){
		if(r==n&&n==-1){
			break;
		}
		else{
			int inp[1010];
			int i,j,k;
			for(i=0;i<n;i++){
				scanf("%d",&inp[i]);
			}
			sort(inp,inp+n);
			int flag=0;
			for(i=0;i<n-1;i++){
//				if(inp[i]==inp[i+1]){//极为先进的去重部分
//					for(k=i;k<n-1;k++){
//						inp[k]=inp[k+1];
//					}
//					n--;
//					flag=1;
//				}
			}
			i=0;
			int ans=0;
			while(i<n){//核心算法了属于是,其实就是一个区间的贪心问题
				int sp=inp[i++];
				while(i<n&&inp[i]<=sp+r){
					i++;
				}
				sp=inp[i-1];
				while(i<n&&inp[i]<=sp+r){
					i++;
				}
				ans++;
			}
			printf("%d\n",ans);
		}
	}
}

反思

最开始用for遍历所有点,显然不合适但不会while,代码实现还是有问题,语言啊...

然后是没分析数据导致多了一步去重,还好写了也没超时hhh

最后是算法里面

while(i<n&&inp[i]<=sp+r){
	i++;
}
sp=inp[i-1];
while(i<n&&inp[i]<=sp+r){
	i++;
}

这一段,最开始while的条件忘了加等号=导致如果有点刚好在sp+r这个位置会被漏掉导致多一次计数

其实真不难,还是太菜了,得多练嗷

posted @ 2022-11-02 17:22  ~Chitoge  阅读(17)  评论(0)    收藏  举报