模拟/递归:约瑟夫问题

        约瑟夫问题是个有名的问题:m个人围成一圈,从第一个开始报数,第n个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。

        简单的方法是用数组做一个模拟,一遍一遍的扫过数组,每经过n个没死的人,数组赋值1表示死亡,直至死亡数等于m,输出最后的人编号。

#include<stdio.h>
int array[1000];
int main(int argc,char* argv[])
{
    int m,n;
    scanf("%d%d",&m,&n);
    int k=0,s=0,died=0;
    do
    {
        k++;
        if(k>m)
            k=1;
        if(!array[k])
            s++;
        if(s==n)
        {
            s=0;
            array[k]=1;
            died++;
        }
    }while(died<m);
    printf("%d\n",k);
    return 0;
}

        ***用数组模拟死亡过程速度太慢了,在网上搜到了快得多的数学方法……

        递归的方法,把每个人的编号先都减一,这样会是0~(m-1)号。

        设第一个死掉的是 ( n-1 )%m 号,所以说之后第二次选谁死的时候,第一个人的编号 0 就是原来的 n%m ,第二个死掉的人的编号 x2 的原编号就是 ( n%m+x2 )%m = ( n+x2 )%m,知道了原理,但这样为什么不会出错呢?不应该剔除掉死掉的家伙吗?因为 x2 肯定是小于 m 的,加起来取余后肯定在上一个死掉的人编号前面,所以不会出现算进去已经死掉的人的问题!

        按照这个思想的话,最后一个死掉( 后面特指'他' )的肯定是编号是0的,因为只剩他自己了吗,所以说这个问题就神奇的转换成了他原来的编号是多少?!!依次迭代即可。

        迭代公式 f ( x ) = ( f ( x-1 ) +n ) % x   ( 1<x<=m ) ,f ( 1 ) = 0

#include<stdio.h>
int main(int argc,char* argv[])
{
    int m,n;
    scanf("%d%d",&m,&n);
    int s=0;
    for(int i=2;i<=m;i++)
        s=(s+n)%i;
    printf("%d\n",s+1);
    return 0;
}

        非常巧妙的方法~

END

猜你喜欢

转载自blog.csdn.net/belous_zxy/article/details/80559903