N个人围成一圈报数,报到某一个数m的就出局,问你最后剩下来的人的号码?

本文详细解析了约瑟夫环问题,通过数学归纳法给出了递归公式,并提供了高效的算法实现。介绍了如何通过循环和模运算求解特定条件下最后一个留在圈中的人的位置。

算法如下:
//函数接收n和m,返回最后出圈的是第几个人
/*e.g.       yuesefu(5,2)=3
                  yuesefu(2,100)=1*/
int   yuesefu(int   n,int   m)
{
        int   i,r=0;
        for   (i=2;i <=n;i++)   r=(r+m)%i;
        return   r+1;
}

 

首先我们作一个这样的约定,
每数完一个m为一轮,
编号从0开始
每数到m之后剩下的人按数数的顺序重新开始编号
e.g,如果n=5   m=7
第1轮       第2轮       第3轮       第4轮
0123401   0123012   0120120   0101010   (编号)
1234567   1234567   1234567   1234567   (数的数字)
0123401   2340234   0230230   2323232   (如果编号一直不变则是这样)
那么第2轮中编号为0的人实际是第1轮中编号为2的人
那么第3轮中编号为0的人实际是第2轮中编号为3的人

k+1轮的编号i的人在k轮中编号为

(m%(n-k+1)+i)mod(n-k+1)
简化为
(m+i)mod(n-k+1)

e.g.
剩下来的人在最后一轮(第n-1轮)的编号为(m   mod   2+0)
那么他在倒数第二轮编号为
(m+m%2)%3

设Ak为倒数第k轮剩下来的人的编号
A1=m%2
A2=(m+A1)%3
A3=(m+A2)%4
....
Ak=(m+Ak-1)%(k+1)

那么算法就出来了

 

这就是Josephus问题
设n个人围成一圈,标号为0..n-1,从第一个人开始依次从1到k循环报数,当报到k的时候此人出圈。设J(n,   k,   i)表示第i个出圈的人的标号。

定理一:
J(n,   k,   1)   =   (k-1)   mod   n,   (n   > =   1,   k   > =   1)                           …………   (1)

证明:
由定义直接得证。 Q.E.D.

定理二:
J(n+1,k,   i+1)   =   (k   +   J(n,   k,   i))   mod   (n+1),     (n   > =   1,   k   > =   1,   1 <=   i   <=   n)   …………   (2)

证明:
设J(n,   k,   i)   =   g,因此如果有n个人,从0开始报号,第i个出圈的标号为g。现在考虑J(n+1,   k,i+1),因为J(n+1,   k,   1)   =   (k-1)   mod   (n+1),即第一步的时候删除数字(k-1)   mod   (n+1),第二步的时候从数字k开始数起。因而问题变为了找到剩下的n个数字中从k开始数起被删除的第i个数字(注意这时(k-1)   mod   (n+1)已经被删除了),而这恰好就是(g+k)   mod   (n+1),(2)成立。   Q.E.D.


根据(2),很容易求得n个数里面第i个出圈的数。


对于k   =   2,   3的情况,直接可以推导出公式来。但是对于k> =4的情况,还没有推导出公式来,目前最好的算法是一个根据估计J(n,   k,   i)上下界的快速算法。


更具体的分析,参见
[1]   Lorenz   Halbeisen,   The   Josephus   Problem,   1994
[2]   Woodhouse,   D.   ,   The   extended   Josephus   problem,   Rev.Mat.   Hisp.-Amer.(4)   33   (1973),   207-218
[3]   Robinson,   W.   J.,The   Josephus   problem,   Math.   Gazette   44   (1960),   47-52
[4]   Jakobczyk,   F.   ,   On   the   generalized   Josephus   problem,   Glasgow   Math.J.14(1973),   168-173

 

http://topic.youkuaiyun.com/t/20021110/16/1164569.html

<think>嗯,用户现在想解决约瑟夫环题,具体是n个人围成一圈报数到3退出,最后剩下一个的原始位置。用户之前提供的三个引用都是关于约瑟夫环的不同实现方法,有Java和C语言的代码示例。我需要综合这些信息,给出一个清晰的解答。首先,约瑟夫环题的核心是模拟这个过程,找到最后剩下的位置。用户提到的是报数到3退出,但可能也希望了解一般情况的解法,比如报数到m的情况。不过当前题明确是报数到3,所以重点应该放在这个具体案例上。用户提供的引用中,引用[1]和[2]使用了组标记法,用0和1表示存在与否,通过循环遍历组,直到只剩一。引用[3]则是C语言的实现,同样用组标记,但结构略有不同。这些方法的时间复杂度都是O(n*m),在n较大时可能效率不高,但对于用户的题来说,可能更关注正确性和可理解性。我需要先解释约瑟夫环题的基本解决思路,比如使用循环组或者链表来模拟报数过程。然后,可以给出递归公式,因为约瑟夫环题有学上的递推解,这样可以在O(n)时间内解决,适用于较大的n。用户可能想知道不同方法的优缺点,比如模拟法虽然直观,但效率低;递归或学方法效率高,但需要理解推导过程。此外,用户可能希望看到具体的代码示例,比如Java或Python的实现,这样他们可以自己测试。还需要注意用户提到的系统级指令,比如学公式要用$...$,代码块要正确格式化,引用文献要标注。例如,递推公式应该用LaTeX格式,如$f(n) =(f(n-1)+ m) \%n$,其中m=3。可能用户没有意识到学解法的重要性,所以需要解释两种方法:模拟法和学递推,并比较它们的适用场景。同时,需要确保回答结构清晰,分步骤讲解,帮助用户逐步理解题。最后,生成相关题时要考虑用户可能进一步的题,比如如何扩展到报数到m的情况,或者优化时间复杂度的方法,以及约瑟夫环的其他变种题。</think>### 约瑟夫环题解法详解 #### 一、题描述 $n$个人围成一圈,从第1开始报数(1-3循环),报数为3的出局最后留下的原始编号是多少? #### 二、核心算法 ##### 1. 模拟法(时间复杂度$O(n \cdot k)$) 使用组标记存在状态,通过循环模拟淘汰过程: ```java public static int josephus(int n) { int[] arr = new int[n]; // 0表示存活,1表示淘汰 int count = 0, alive = n, pos = 0; while (alive > 1) { if (arr[pos] == 0) { count++; if (count == 3) { arr[pos] = 1; count = 0; alive--; } } pos = (pos + 1) % n; // 环形遍历 } for (int i = 0; i < n; i++) { if (arr[i] == 0) return i + 1; } return -1; } ``` **实现要点**: - 环形遍历使用取模运算`pos = (pos + 1) % n`[^1] - 每次报数到3时重置计器并标记淘汰者[^2] - 空间复杂度$O(n)$,适用于小规模据 ##### 2. 学递推法(时间复杂度$O(n)$) 利用递推公式直接计算结果: $$ f(n) = (f(n-1) + 3) \% n \quad (f(1) = 0) $$ 当$n > 1$时,递推计算到$f(n)$后,最终结果为$f(n) + 1$ ```python def josephus(n): pos = 0 for i in range(2, n+1): pos = (pos + 3) % i return pos + 1 ``` **学推导**: 1. 当只剩1时,位置为0(编号1) 2. 每增加1,新位置为$(原位置 + 3) \% 当前$[^3] 3. 最终结果需要+1转换为自然编号 #### 三、方法对比 | 方法 | 时间复杂度 | 空间复杂度 | 适用场景 | |------------|------------|------------|------------------------| | 模拟法 | $O(3n)$ | $O(n)$ | 直观理解,小规模据 | | 学递推法 | $O(n)$ | $O(1)$ | 高效计算,大规模据 | #### 四、扩展应用 1. **变种题**:将3改为任意$m$,只需修改递推公式中的常项 2. **动态调整**:当$m$随轮次变化时的解法(需修改递推关系) 3. **循环链表实现**:使用链表结构模拟更直观(但时间复杂度相同)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值