POJ—3069—Saruman's Army—【贪心】

来源:互联网 发布:淘宝店铺图片轮播尺寸 编辑:程序博客网 时间:2024/06/15 23:35

Saruman's Army
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 3967 Accepted: 2033

Description

Saruman the White must lead his army along a straight path from Isengard to Helm’s Deep. To keep track of his forces, Saruman distributes seeing stones, known as palantirs, among the troops. Each palantir has a maximum effective range of R units, and must be carried by some troop in the army (i.e., palantirs are not allowed to “free float” in mid-air). Help Saruman take control of Middle Earth by determining the minimum number of palantirs needed for Saruman to ensure that each of his minions is within R units of some palantir.

Input

The input test file will contain multiple cases. Each test case begins with a single line containing an integer R, the maximum effective range of all palantirs (where 0 ≤ R ≤ 1000), and an integer n, the number of troops in Saruman’s army (where 1 ≤ n ≤ 1000). The next line contains n integers, indicating the positions x1, …, xn of each troop (where 0 ≤ xi ≤ 1000). The end-of-file is marked by a test case with R = n = −1.

Output

For each test case, print a single integer indicating the minimum number of palantirs needed.

Sample Input

0 310 20 2010 770 30 1 7 15 20 50-1 -1

Sample Output

24

Hint

In the first test case, Saruman may place a palantir at positions 10 and 20. Here, note that a single palantir with range 0 can cover both of the troops at position 20.

In the second test case, Saruman can place palantirs at position 7 (covering troops at 1, 7, and 15), position 20 (covering positions 20 and 30), position 50, and position 70. Here, note that palantirs must be distributed among troops and are not allowed to “free float.” Thus, Saruman cannot place a palantir at position 60 to cover the troops at positions 50 and 70.


看样例:70,30,1,7,15,20,50

先从小到大排序:1,7,15,20,30,50,70

R=10,从左往右

第一个:如果放在1,能覆盖7,但是放在1 肯定是不划算的,因为左边没东西,浪费。。。所以往右,因为1必须要被覆盖,所以选在放在1的时候,它覆盖范围最右端的,就是7,放在7上,1和15都能被覆盖。

第二个:1,7,15都被覆盖掉了,可以抹去不看,20成了最左端,重复上面步骤,如果放在20,则它范围最右端是30,所以第二个放在30,能覆盖20和30

第三个:如果放在50,覆盖范围最右端就是它自己50,所以放在50

第四个:如果放在70,覆盖范围最右端就是它自己70,所以放在70


所以贪心策略就是:从小到大排序后,从未被覆盖的最左端开始,先假设放在最左端,找到它覆盖范围内最右端的,放在那,把能覆盖的都标记,然后重复,直到所有都被标记

所以每次需要两个步骤,可以用temp记录,当temp=2的时候,开始新的一次


上代码:


#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <cstdlib>using namespace std;int Army[1010];     //记录每个所在的位置bool used[1010];    //判断是否被覆盖bool cmp(int a,int b){    return a<b;}int main(){    int R,n;    while(scanf("%d%d",&R,&n)!=EOF)    {        if(R==-1 && n==-1)            break;        for(int i=0;i<n;i++)            scanf("%d",Army+i);        sort(Army,Army+n,cmp);        memset(used,false,sizeof(used));    //全部设为没有被覆盖        int countn=0,temp=0;    //countn就是所要求的最少要几个,temp是根据贪心策略的需要而设置的        int i,j;    //i遍历Army[]数组        for(i=0;i<n;)        {            temp++; //覆盖一次            if(!used[i])                countn++;   //如果是新的开始,就需要一个            used[i]=true;   //标记掉。。。            for(j=i+1;j<n && Army[i]+R>=Army[j];j++)                used[j]=true;   //往右找在它范围内的,全部标记,最终j是第一个在范围外的那个            if(temp==2) //根据贪心策略,当temp==2,说明一轮已经结束            {                temp=0; //开始新一轮                i=j;    //j是范围外的,从它开始新的覆盖            }            else                i=j-1;  //j-1是范围内最远的,再以它为中心,覆盖        }        printf("%d\n",countn);    }    return 0;}


看到网上有和我一样思路,但是代码比我简介多了的,不需要用来标记的used[]数组,学习了~~~!!!:

传送门:http://blog.csdn.net/z309241990/article/details/17510483


自己也来实现一遍:


#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>using namespace std;int Army[1010];    //还是用来记录数组bool cmp(int a,int b){    return a<b;}int main(){    int R,n;    while(scanf("%d%d",&R,&n)!=EOF)    {        if(R==-1 && n==-1)            break;        for(int i=0;i<n;i++)            scanf("%d",Army+i);        sort(Army,Army+n,cmp);  //从小到大排序        int i=0,countn=0;        while(i<n)        {            int s=Army[i++];    //从未被标记的最左端开始            while(i<n && s+R>=Army[i])  //最后i是第一个在范围外的                i++;            s=Army[i-1];    //s=范围内最右端的            while(i<n && s+R>=Army[i])  //再以那个为中心,向右找能覆盖的                i++;            countn++;   //上面的两个循环就能确定一个放置的地方,所以数量加1        }        printf("%d\n",countn);    }    return 0;}


0 0
原创粉丝点击