美文网首页
约瑟夫问题规律讨论

约瑟夫问题规律讨论

作者: 江海小流 | 来源:发表于2020-03-05 10:24 被阅读0次

考虑这样一个问题,有 n 个人,标号从 1n,从第一个人开始数,杀死数到 3 的人,然后下一个人重新开始数。
问:最后死的人是几号?

假设有 10 个人,将没有被杀的人重新编号,那么,杀人情况如下表所示

1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22
23 24 25
26 27
28
29
30

第一轮杀了 3 号、6 号和 9 号,1 号变成了 11 号,2 号变成了 12 号等等。

我们可以发现如下性质:

  • 每一轮被杀的了人的编号是 3 的倍数,且第 k 个被我要的杀的人的当前轮的编号是 3k
  • 3k 号被杀后,下一个被杀的人是 3k+3 号,那么 3k+1 号和 3k+2 号是暂时安全的,因此需要对其编号,其新的编号为 n + 2k + 1n + 2k + 2,因为杀完 3k 号后相当于杀了 k 个人,还有 n - k 个人。

因此对于第 n 个被杀死的人,他死亡时编号为 N = 3n,又因为 N = n + 2k + 1N = n + 2k + 2,显然 k = \lfloor \frac {N - n - 1} {2} \rfloor,而上一轮的编号为 N' = k + N - n
因此可以用下面的方法算出最后一个死的人的原编号

int J(int n) {
    int i = 3 * n;
    while (i > n) i = (i - n - 1) / 2 + i - n;
    return i;
}

如果用 N = 3n + 1 - D 来替换 N,发现原迭代式变为 D = \lceil \frac {3}{2} D \rceil

则可以用以下方法求出上面要求的结果

int J(int n) {
    int i = 1;
    while (i <= 2*n) i = ceil(3.0 * i / 2);
    return 3*n + 1 - i;
}

当然,如果循环节的个数不为 3,而是为 q,可以用相同的方法证明,有类似的结论

int J(int n, int q) {
    int i = 1;
    while (i <= (q - 1) * n) d = ceil((double)q * i / (q - 1));
    return q*n + 1 - i;
}

相关文章

  • 约瑟夫问题规律讨论

    考虑这样一个问题,有 个人,标号从 到 ,从第一个人开始数,杀死数到 的人,然后下一个人重新开始数。问:最后...

  • 约瑟夫问题

    今天看了一下约瑟夫问题,嗯,感觉自己智商欠费:( 还是来总结下好啦~ 问题 约瑟夫是犹太军队的一个将军,在反...

  • 约瑟夫问题

    题目:0,1,...,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下...

  • 约瑟夫问题

    要是你怎么制定游戏规则? 现在有前面15个好人和后面15个坏人,他们围成一圈。现在从第一个好人开始,数到第n个人就...

  • 约瑟夫问题

    问题来源 据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephu...

  • 约瑟夫问题

    源文件josephus.c

  • 约瑟夫问题

    约瑟夫问题 一、数组解法 二、循环队列 三、数学解法

  • 约瑟夫问题

    一、约瑟夫问题介绍 1、约瑟夫问题原题:n个小孩子手拉手围成一个圈,编号为k(1 <= k <= n )的人从1开...

  • 约瑟夫问题

    找到首节点、创建一个节点记录遍历当前节点的前一个节点、创建一个计数器,当计数器的值为3的时候,将该节点从链表中移除...

  • 约瑟夫问题

    大家自行百度下约瑟夫问题,这里用golang+单向循环链表的方式解决约瑟夫问题,下面先提供一下代码: func (...

网友评论

      本文标题:约瑟夫问题规律讨论

      本文链接:https://www.haomeiwen.com/subject/glstrhtx.html