约瑟夫问题

来源:互联网 发布:淘宝客服工作总结1 编辑:程序博客网 时间:2024/06/10 11:53

以前搞acm的时候,做的最少的就是数论这种题目了,可以说是完全不会,曾经接触过约瑟夫问题,如果作为一个模拟,给初学者做做挺好的,但是它居然有公式,而且公式和mod扯上了关系,乍一看以为又是和数论有关,其实,它最主要的是一个递归子问题,也是我比较喜欢的问题之一。

约瑟夫问题,有n个人,编号从0到n-1围成一个圈,从1开始,数m个,然后把第m个从这个圈中剔除,然后继续从1开始数m个,再剔除这个人,直到这个圈只有1个人,这个人就是胜利者。那么就是输入m和n,让你输出胜利者的编号。

初学者可以试试模拟,也能做,但是对于n和m比较大的情况,效率略低。

关于子问题:

假如现在编号为0到n-1,那我们找出来的第一个人编号是(m-1)%n,找出来之后,此时可以看做一个规模n-1的约瑟夫环,只是编号变了,编号变化如下:

(m-1)%n+1       0

(m-1)%n+2       1

(m-1)%n+3       2

...............              ...

(m-1)%n-1      n-2

假如我知道右边一栏的问题(就是规模是n-1的问题)的答案是编号X,那么我只要把X对应到左边的编号,就是规模为n的问题的答案。那么我们需要一个将右边的数变成左边的数的方法,有:

左=(右+m)%当前的规模n

可以用如下方法推导:

f[i]表示在i个人情况下能过存活的人的编号,那么易得f[1]=0,

然后根据刚才的递归公式得到:

for(i=2;i<=n;i++)

f[i]=(f[i-1]+m)%i;

f[n]即为最后的结果

至此约瑟夫问题可以解决了。

0 0
原创粉丝点击