约瑟夫斯问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环

有n个囚犯站成一个圆圈,准备处决。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。

接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。

问题是,给定了n和k,一开始要站在什么地方才能避免被处决?

问题是以弗拉维奥·约瑟夫斯命名的,它是1世纪的一名犹太历史学家。他在自己的日记中写道,他和他的40个战友被罗马军队包围在洞中。他们讨论是自杀还是被俘,最终决定自杀,并以抽签的方式决定谁杀掉谁。约瑟夫斯和另外一个人是最后两个留下的人。约瑟夫斯说服了那个人,他们将向罗马军队投降,不再自杀。约瑟夫斯把他的存活归因于运气或天意,他不知道是哪一个。

解法

1.用循环单链表模拟整个过程,时间复杂度是O(n*m)

2.如果只是想求得最后剩下的人,则可以用数学推导的方式得出公式。

要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。因此如果要追求效率,就要打破常规,实施一点数学策略。

为了讨论方便,先把问题稍微改变一下,并不影响原意:
问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。

我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):
  k  k+1  k+2  ... n-2, n-1, 0, 1, 2, ... k-2并且从k开始报0。
现在我们把他们的编号做一下转换:

k     --> 0
k+1   --> 1
k+2   --> 2
...
...
k-2   --> n-2
k-1   --> n-1
变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x'=(x+k)%n

如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!好了,思路出来了,下面写递推公式:

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

递推公式
f[1]=0;
f[i]=(f[i-1]+m)%i;  (i>1)

有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1
由于是逐级递推,不需要保存每个f[i],程序也是异常简单:

#include <stdio.h>
int main()
{
int n, m, i, s = ;
printf ("N M = ");
scanf("%d%d", &n, &m);
for (i = ; i <= n; i++)
{
s = (s + m) % i;
}
printf ("\nThe winner is %d\n", s+);
}

这个算法的时间复杂度为O(n),相对于模拟算法已经有了很大的提高。算n,m等于一百万,一千万的情况不是问题了。可见,适当地运用数学策略,不仅可以让编程变得简单,而且往往会成倍地提高算法执行效率。

相比之下,解法二的优越性不言而喻,同时说明数学确实很重要。

http://blog.csdn.net/wuzhekai1985/article/details/6628491

http://www.cnblogs.com/EricYang/archive/2009/09/04/1560478.html

组合数学--约瑟夫环问题 Josephus的更多相关文章

  1. 约瑟夫环问题(Josephus)

    约瑟夫环:用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至最后一个元素并输出该元素的值. 一.循环链表:建立一个有N个元素的循环链表,然后从链表头开始遍历并记数,如果计数值为M,则 ...

  2. 谁能笑到最后,约瑟夫环-Josephus问题求解

     一. 简述Josephus问题 N个人站成一环,从1号开始,用刀将环中后面一个人“消灭“”掉,之后再将刀递给下一个人,这样依次处理,最后留下一个幸存者. 二. 求解方法  1.  约瑟夫问题如果使用 ...

  3. LightOJ - 1179 Josephus Problem(约瑟夫环)

    题目链接:https://vjudge.net/contest/28079#problem/G 题目大意:约瑟夫环问题,给你n和k(分别代表总人数和每次要数到k),求最后一个人的位置. 解题思路:因为 ...

  4. Josephus环的四种解法(约瑟夫环)

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

  5. 单向环形链表解决约瑟夫环(Josephus)问题

    一.约瑟夫环问题 Josephu 问题为:设编号为1,2,- n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那 ...

  6. 约瑟夫环的java解决

    总共3中解决方法,1.数学推导,2.使用ArrayList递归解决,3.使用首位相连的LinkedList解决 import java.util.ArrayList; /** * 约瑟夫环问题 * 需 ...

  7. 简洁之美 -约瑟夫环的python 解法

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

  8. 约瑟夫环 --- 面向对象 --- java代码

    约瑟夫环 的 面向对象 解法 罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个 ...

  9. Roman Roulette(约瑟夫环模拟)

    Roman Roulette Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...

随机推荐

  1. Python的实现分类

    目前流行的Python实现包括CPython,Jython,IronPython,Stackless,PyPy,Cython,Shed Skin. CPython Cpython是Python的标准实 ...

  2. 自测之Lesson4:gdb

    题目:列出gdb过程中常用的命令. 常用命令: 命令 作用 使用示例1 使用示例2 list 列出代码 list 行号 list 函数名 break 设置断点 break 行号 b 行号 run 运行 ...

  3. 软工实践Alpha冲刺(3/10)

    队名:我头发呢队 组长博客 作业博客 杰(组长) 过去两天完成了哪些任务 继续翻阅Google Material Design 2的官方文档 接下来的计划 音源爬取 还剩下哪些任务 app开发 燃尽图 ...

  4. DAY2敏捷冲刺

    站立式会议 工作安排 (1)服务器配置 (2)数据库连接 (3)页面创意 燃尽图 代码提交记录 感想 林一心:centos配置服务器真的算是一个不小的坑,目前数据库配置清楚,脚本部署好明天测试交互,还 ...

  5. Java中终止正在运行线程

    问题:java 中如何让一个正在运行的线程终止掉? Demo_1: class TT implements Runnable { private boolean flag = true; @Overr ...

  6. TCP系列16—重传—6、基础快速重传(Fast Retransmit)

    一.快速重传介绍 按照TCP协议,RTO超时重传是一个非常重要的事件,当RTO超时的时候,TCP会同时通过两种方式非常谨慎的降低发送数据包的速率,一种是基于拥塞控制削减发送窗口的大小,另外一个是通过指 ...

  7. OSG学习:移动/缩放/旋转模型

    移动和缩放以及旋转都是对矩阵进行操作,这些操作如果要叠加直接矩阵相乘就可以了. 下面的示例代码中,加入了四个bignathan,一个是默认加入在最中间,一个向上移2单位,一个是向下移2单位且缩放0.5 ...

  8. Jedis源码解析——Jedis和BinaryJedis

    1.基本信息 先来看看他们的类定义: public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommands ...

  9. SQL SERVER技术内幕之4 子查询

    最外层查询的结果集会返回给调用者,称为外部查询.内部查询的结果是供外部查询使用的,也称为子查询.子查询可以分成独立子查询和相关子查询两类.独立子查询不依赖于它所属的外部查询,而相关子查询则须依赖它所属 ...

  10. getGeneratedKeys自动获取主键的方法

    public class Demo { public static void main(String[] args) { try { String sql="insert into pers ...