严蔚敏算法约瑟夫环_求自然语言解释:约瑟夫环之递归算法?

递归解法的关键:找到n个人参加游戏的获胜者编号和n-1个人参加游戏的获胜者编号之间的联系,即递归表达式如何得出。

我们假设有n个人参加游戏,这n个人的编号分别是:

队列(1):1, 2, 3, 4, 5, 6, … , n,共n个。

这n个人横着排成一排报数,为了方便理解起见,假设k=1,m=5(即从编号1开始报数,报到5的出列,一排报完了后回到队列开头接着报。)(这样的报数跟围成一圈报数是一模一样的,不影响结果。为什么变成横着排?为了便于理解。)

第一次报数:淘汰的编号是4%n+1(若开始总人数大于等于5,那么淘汰5号),剩下n-1个人组成的队列重新开始报数,但是这时候队列是从编号6开始报数的,那么我们可以写成:

队列(2):6,7,8,…,n-1,1,2,3,4,共n-1个

对于队列(1)和队列(2)来说,获胜者的编号是一样的(因为区别仅仅是经过了一轮报数而已),但是获胜者在两个队列中的位置变换了。

现在关键的地方来了:

对于这个n-1个人组成的队列(2),假设获胜者位于其中的某个位置(比如第3个位置的编号8最终会获胜),那么对于下面的n-1个人组成的队列:

队列(3):1,2,3,4,5,…,n-1,共n-1个

这两个队列的获胜者在队列中的位置是一样的(如果上面的队列(2)是第3名编号8获胜,那么对于下面这个队列(3),一定也是第3名编号3获胜。因为最后获胜者只跟游戏开始时的初始位置相关。)

而下面的队列(3),正好是n-1个人参加游戏时的队列排列情况。我们把这个队列的获胜者编号记为f(n-1),而队列(1)的获胜者编号记为f(n),这样f(n)和f(n-1)的关系正好就是我们要找的n个人参加游戏的获胜者编号和n-1个人参加游戏的获胜者编号之间的联系,这个联系就可以通过队列(2)这个桥梁来找出来。

现在我们要从f(n-1)递归得到f(n),也就是要找出队列(3)与队列(1)的关系,那么首先找出队列(3)和队列(2)的关系,而这个关系就是:获胜者的位置是相同的。我们举个例子看下,假设队列(2)和队列(3)都是8个人,也就是令n=9,即:

队列(2):6,7,8,9,1,2,3,4(由原先9个人的队列经过1轮后得到)

队列(3):1,2,3,4,5,6,7,8

大家看下上下两排有什么规律?相同位置的编号关系:

1+5=6,2+5=7,3+5=8,4+5=9,5-4=1,6-4=2,7-4=3,8-4=4

似乎没什么规律?但是如果把5-4=1写成5+5-9=1,6-4=2写成6+5-9=2,7-4,8-4以此类推,正好是它们对9取余数!也就是说,假设队列(3)的编号为x,队列(2)相同位置的编号为y,那么y=(x+5)%9,但是这个规律对x=4、y=9时不成立!那么怎么办呢?很简单的一个办法,我们可以想到,把队列(2)和队列(3)的每个元素都减去1,即:

队列(2)--> 队列(4):5,6,7,8,0,1,2,3

队列(3)--> 队列(5):0,1,2,3,4,5,6,7

那么对于队列(4)和队列(5)来说,y=(x+5)%9就全部成立了!这里%后面的数字是9,正好就是n的值(n=9)。

而f(n)=y+1, f(n-1)=x+1,因此:

f(n)-1=( f(n-1)-1+5)%n,整理一下,即:

f(n) =( f(n-1)+4)%n+1

通用的表达式就是f(n)=(f(n - 1) + m - k) % n + 1

于是,可以得到递归程序(Python)如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值