问题描述:

约瑟夫环问题(Josephus)
用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。

解法一:

思路:建立一个有N个元素的循环链表,然后从链表表头遍历并记数,如果计数i==m(i初始为1)删除元素,依次类推,若当前元素等于该元素链接的下一元素时终止循环。

解法二:

用数学归纳法递推。

无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),若nm非常大,无法在短时间内计算出结果。我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。因此如果要追求效率,就要打破常规,实施一点数学策略。

为了讨论方便,先把问题稍微改变一下,并不影响原意:
问题描述: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 = 0;
    printf ("N M = ");
    scanf("%d%d", &n, &m);
    for (i = 2; i <= n; i++)
    {
       s = (s + m) % i;
    }
    printf ("\nThe winner is %d\n", s+1);
}

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

转载于:https://www.cnblogs.com/clive/archive/2009/10/27/Mathematic_Method_of_Josephus_Ring.html

求约瑟夫环问题最后胜利者的一般解法以及数学推导方法相关推荐

  1. 这样给面试官解释约瑟夫环问题的几种巧妙解法,面试官满意的笑了

    转载请联系公众号:bigsai 前言 约瑟夫环问题是算法中相当经典的一个问题,其问题理解是相当容易的,并且问题描述有非常多的版本,并且约瑟夫环问题还有很多变形,这篇约瑟夫问题的讲解,一定可以带你理解通 ...

  2. 约瑟夫环问题(数学递推法)

    约瑟夫环问题起源于一个犹太故事: 罗马人攻占了桥塔帕特,41个人藏在一个山洞中躲过了这场浩劫.这41个人中,包括历史学家Josephus(约瑟夫)和他的一个朋友.剩余的39个人为了表示不向罗马人屈服, ...

  3. 线性表进阶___约瑟夫环问题

    /*** 解决约瑟夫环问题:古代某法官要判决n个犯人,荒唐的法律:将犯人站成一个圈,从第S个人开始数起* 每数到第D个犯人,就拉出来处决,再从下一个开始数D个,数到的人再处决,直到剩下最后一个犯人予以 ...

  4. 【数据结构与算法】 01 链表 (单链表、双向链表、循环链表、块状链表、头结点、链表反转与排序、约瑟夫环问题)

    一.线性表 1.1 概念与特点 1.2 线性表的存储结构 1.3 常见操作 1.4 应用场景 二.链表 2.1 链表简介 2.2 单向链表(单链表) 2.21 基本概念 2.22 单链表基本操作 2. ...

  5. 【C++代码】约瑟夫环问题:0,1,……,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。

    问题描述:0,1,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字.求出这个圆圈里剩下的最后一个数字. 这是力扣上的一道题.我的思路: ①首先想到的是用循环链表,每次向后遍历 ...

  6. 【约瑟夫环】Java实现:100个人开始从1开始报数,每当报数到3,报数3的人离开,求最后留下来人的位置。

    [约瑟夫环]Java实现:100个人开始从1开始报数,每当报数到3,报数3的人离开,求最后留下来人的位置. 原创 2017年03月15日 00:21:36 标签: 约瑟夫环问题 1023 问题背景:约 ...

  7. 约瑟夫环(约瑟夫问题)求最后出列的人数

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

  8. 约瑟夫环问题,n个人围成一圈,依次按1、2.....m来报数,报数值为m的人出圈,求最后出圈的人和出圈的序列

    约瑟夫环问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题.在计算机编程的算法中,类似问题又称为约瑟夫环.又称"丢手绢问题".),也就是如下图这个样子: 简单来讲就 ...

  9. java实现简单的约瑟夫环问题(二)

    Josephus(约瑟夫)问题的数学方法 前面的内容都是直接来来自于百度百科,后面才是我对这段话的理解 无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间 ...

最新文章

  1. linux cmake 多线程 错误 undefined reference to 'pthread_create'
  2. swing GeneralPath::cubicTo绘制平滑曲线
  3. 结构体怎么赋值_Go 经典入门系列 16:结构体
  4. 线性时间查找固定频率的元素
  5. Windows Sockets 2.0 新特性
  6. SAP CRM email office integration
  7. java: 错误: 不支持发行版本 5
  8. python中的计算符号
  9. 操作失败10秒内未完成启动服务mysql_01-MySQL 命令行-cmd用法-未完成
  10. mysql nhibernate_C#连接Mysql数据库NHibernate
  11. Notepad++ 配置java编译环境
  12. layui totalRow 多层嵌套json_自定义 Behavior,实现嵌套滑动、平滑切换周月视图的日历...
  13. android之mipmap文件夹
  14. python随手记自动记账_简化记账——我的“随手记”
  15. 解决Chrome浏览器主页被hao123、360和2345篡改简单有效方法
  16. Ant下载安装及使用详解
  17. 用文件流下载文件( Blob)时各种类型文件的 type 整理
  18. java小游戏实训目的_Java弹球小游戏实验报告.doc
  19. ArcGIS 地理数据库(GDB)/Tolerance/Resolution简介
  20. dw html压缩文件,如何压缩css文件?

热门文章

  1. 微软进一步融合 Linux,VS Code 官方支持树莓派
  2. 开始使用Power BI桌面
  3. win10 SQL SERVER 2017安装详解
  4. js 格式化 java时间格式化_用JavaScript(js)对时间格式化
  5. mysql jdbc百度_mysql8.0 jdbc连接注意事项
  6. mybatis日期范围查询_15. Django 2.1.7 模型 条件查询、模糊查询、空查询、比较查询、范围查询、日期查询...
  7. 基于matlab的车牌定位算法设计与实现,matlab车牌定位系统设计(源码+文档)
  8. Python设置画布大小_Python第25课:海龟绘图_自定义函数的应用
  9. linux hadoop 伪分布,linux配置Hadoop伪分布安装模式
  10. python 排列组合_Python计算生态jieba库和random库的综合运用之爬山篇