约瑟夫环问题

参考文章

约瑟夫环之二(用递归的思想解决Josephus问题)

解释

约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

解法

初始情况: 0, 1, 2 ......n-2, n-1 (共n个人)

第一个人,编号一定是(m-1)%n(或者写成m%n-1)出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k==m%n的人开始):

k k+1 k+2 ... n-2, n-1, 0, 1, 2, ...,k-3, k-2

现在我们把他们的编号做一下转换:

x' --> x的情况

k --> 0
k+1 --> 1
k+2 --> 2
...
...
k-2 --> n-2

变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗!

x ->x'?(这正是从n-1时的结果反过来推n个人时的编号!)
0 -> k
1 -> k+1
2 -> k+2
...
...
n-2 -> k-2

变回去的公式 x'=(x+k)%n   (注:k=m%n)

那么,如何知道(n-1)个人报数的问题的解?只要知道(n-2)个人的解就行了。(n-2)个人的解呢?只要知道(n-3)的情况就可以了 ---- 这显然就是一个递归问题:

令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果就是f[n]

递推公式

f[1]=0;

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

代码

#include <stdio.h>
int main() {
    int n, m, i, result;
    while (scanf("%d", &n) == 1) {
        if (!n) {
            break;
        }
        scanf("%d", &m);
        result = 0;
        for (i = 2; i <= n; i++) {
            result = (result + m) % i;
        }
        printf("%d\n", result + 1);
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编...
    xinggang阅读 4,753评论 0 1
  • 好久没有看有关算法的问题了,今天废了不少劲,再感叹一句:要想学好算法就要常练习,没什么捷径可走。废话不多说,如下:...
    时间已静止阅读 11,800评论 0 11
  • 百度百科: 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆...
    KPort阅读 9,317评论 0 4
  • 940万考生的战争结束了,管它多年以后谁胜谁负。当下的生活还要继续,等着大学录取通知书成了幸福的期待,也有很多从此...
    白墨黑阅读 1,652评论 0 3
  • A:作为领导层1要善于给下属提问(通过提问来引导下属思考以及做方案,而不是不理不睬,一棍子挡回去,同时也要预防猴子...
    我来学而时习之阅读 1,162评论 0 0

友情链接更多精彩内容