运用筛法思想解决其他题目。选太子(select the prince)和幸运的编号

我觉得筛法的本质是将符合某特定条件的数标记,并以标记为依据将这些数跳过。
对于幸运的编号这一题,我觉得就可以运用筛法的思想。

描述: 有n个人围成一圈,顺序编号。从第一个人开始报数(从1到m),凡报到m的人退出。问最后一个人的编号是多少?
输入:
输入两个正整数n和m
输出: 最后一个人的编号。
输入样例: 5 2
输出样例: 3

这道题比较难的地方我觉得主要有两个:
1.围成一圈怎么解决?
2.一个人退出后紧接着下一个人重新开始报数,必须跳过之前退出的人。

为了解决第一个问题,我的想法是把圈掰成列,定义一个数组a[j],数组的长度由过程中要转的圈数(可以比要转的实际圈数大)乘以总人数确定,j除以人数所得余数是这个人的编号。
如:有5人,每次报2个数时;
最少转3圈,数组就是a[15];
a[2],a[7],a[12]都代表编号为2的人。
为了解决第二个问题,我觉得应该使用筛法,将所有报数报到m的人即所有代表他们的数都标记为0。
如编号为2的人第一个报到2,将a[2],a[7],a[9]都标记为0。

#include<stdio.h>
int main()
{
    int m,n,c,count=0,b,i,j,a[10000];
    scanf("%d%d",&m,&n);
    c=(m/n+1)*(m-1)*m;
    b=m-1;
    for(i=1;i<=c;i++)
    {
        a[i]=1;
    }
    for(i=1;1<=c;i++)
    {
        if(a[i])
        {
            count++;//相当于在报数
        }
        if(count==n)//当报数报道n时
        {
            a[i]=0;
            count=0;
            b-=1;//记录筛出了多少个人
            for(j=1;j<=c;j++)
            {
                if(j%m==i%m)
                {
                    a[j]=0;
                }
            }
        }
        if(b==0)//当筛出到只剩一个人时,输出并退出循环
        {
            for(j=i;j<=c;j++)
            {
                if(a[j])
                {
                 printf("%d\n",j%m);//bug:j为m的倍数时输出的是零。 
                 break;
                }
            }
            break;
        }
    }

}

选太子用的也是一样的想法。

描述:
某皇帝有2m个儿子,现在要从中选出一个做太子,皇帝不知道该把那一个皇子立为太子,于是决定用下面的方法来选出太子,设每个太子的编号分别1、2、3、…、2m,按顺时针方向站成一个圆圈,现在从1号太子开始按顺时针方向数,数到第n个人,把他淘汰出局,然后从他的下一个人开始上述过程,当第m个人被淘汰时,转变方向继续从1开始数,重复上述过程,最后剩下的皇子将被立为太子。现在请你写一个程序,计算出几号皇子将被立为太子。
输入:
输入两个正整数m n
Input two positive integer.
输出:
输出太子的编号
Output the number.
输入样例:
3 2
输出样例:
1

#include<stdio.h>
int main()
{
    int m,n,c,count=0,b,i,j,a[10000];
    scanf("%d%d",&m,&n);
    c=(2*m/n+1)*2*m*m;
    b=0;
    for(i=1;i<=c;i++)
    {
        a[i]=1;
    }
    for(i=1;1<=c;i++)
    {
        if(a[i])
        {
            count++;
        }
        if(count==n)
        {
            a[i]=0;
            count=0;
            b+=1;
            for(j=1;j<=c;j++)
            {
                if(j%(2*m)==i%(2*m))
                {
                    a[j]=0;
                }
            }
        }
        if(b==m)
        {
            break;
        }
    }
    i=c-2*m+(i-1)%(2*m);//不能用之前的i,因为可能出现i--到0,但选太子过程还没有结束的情况,所以要用能表示当前编号最大的i
    for(i=i;i>0;i--)
    {
        if(a[i])
        {
            count++;
        }
        if(count==n)
        {
            a[i]=0;
            count=0;
            b+=1;
            for(j=1;j<=c;j++)
            {
                if(j%(2*m)==i%(2*m))
                {
                    a[j]=0;
                }
            }
        }
        if(b==(2*m)-1)
        {
            for(j=i;j>0;j--)
            {
                if(a[j])
                {
                 if(j%(2*m)==0) printf("%d\n",2*m);
                 else printf("%d\n",j%(2*m));
                 break;
                }
            }
            break;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值