约瑟夫环的数学公式推导_约瑟夫出圈问题公式-程序员宅基地

约瑟夫环的数学方法解决

 

       编写约瑟夫环程序时会发现,当我们把整个报数过程的人数N变的很大,例如到几百万,虽然在最后还是只剩下两个人报数,但也要循环几百万次才能确定最后留下来的那个人。这样程序执行的效率不高,会占用大量时间去执行循环的过程。有时会发生输出一直等待很长时间才能出来结果。经过查询资料,找到了约瑟夫环的数学解决方法,以及它的算法具体执行的过程来做分享。

 

我们假设 N是约瑟夫环中的总人数  M是规定报数的第几个人出列,一般我们规定是3。

一般的实现方法是用数组,链表的实现更为简单一些,方便删除数据。

这里使用数学方法,只需要找出来其中的规律即可得出结果,不需要通过数组或链表来实现。

下面详细介绍算法的具体推算过程:

 

问题:将编号为0~(N–1)这N个人进行圆形排列,按顺时针从0开始报数,报到M–1的人退出圆形队列,剩下的人继续从0开始报数,不断重复。求最后出列者最初在圆形队列中的编号。

这里从0开始,M-1相当于从第一个人报数开始时的M。

 

下面首先列出0~(N–1)这N个人的原始编号如下:

 

     0  1   2   3   4   … N-3   N-2  N-1

 

第一个出列人的编号一定是(M–1)%n。

       例如,在41个人中,若报到3的人出列,则第一个出列人的编号一定是(3–1)%41=2,注意这里的编号是从0开始的,因此编号2实际对应以1为起点中的编号3。根据前面的描述,m的前一个元素(M–1)已经出列,则出列1人后的列表如下:

 

 

    0  1  …  M-3  M-2  M-1   M   M+1  … N-2  N-1

 

 

     根据规则,当有人出列之后,下一个位置的人又从0开始报数,则以上列表可调整为以下形式(即以M位置开始,N–1之后再接上0、1、2……,形成环状):

 

    M   M+1  … N-2  N-1     0  1  …  M-3  M-2

按上面排列的顺序重新进行编号,可得到下面的对应关系:

      M   M+1  … N-2  N-1     0  1  …  M-3  M-2

      0      1                  …      …          N-3   N-2

        即,将出列1人后的数据重新组织成了0~(N–2)共N–1个人的列表,继续求n–1个参与人员,按报数到M–1即出列,求解最后一个出列者最初在圆形队列中的编号。

 

      通过一次处理,将问题的规模缩小了。即,对于N个人报数的问题,可以分解为先求解(N–1)个人报数的子问题;而对于(N–1)个人报数的子问题,又可分解为先求[(N–1)–1]人个报数的子问题,……。

 

       问题中的规模最小时是什么情况?就是只有1个人时(N=1),报数到(M–1)的人出列,这时最后出列的是编号为0的这个人。因此,可设有以下函数:

 

                               F(1)=0

 

       那么,当N=2,报数到(M–1)的人出列,最后出列的人是谁?应该是只有一个人报数时得到的最后出列的序号加上M,因为报到M-1的人已出列,只有2个人,则另一个出列的就是最后出列者,可用公式表示为以下形式:

 

                             F(2)=F(1)+M

 

 

 

通过上面的算式计算时,F(2)的结果可能会超过N值(人数的总数)。例如,设N=2,M=3(即2个人,报数到2时就出列),则按上式计算得到的值是:

                    

                           F(2)=F(1)+M=0+3=3

一共只有2人参与,编号为3的人显然没有。怎么办?由于是环状报数,因此当两个人报完数之后,又从编号为0的人开始接着报数。根据这个原理,即可对求得的值与总人数N进行模运算,即:

 

                           F(2)=[F(1)+M]%2

验证:                F(2)=[F(1)+M]%2

                                  =[(0+3)]%2

                                   =1

 

       即,N=2,M=3(即有2个人,报数到3–1的人出列)时,循环报数最后一个出列的人的编号为1(编号从0开始)。推算一下,当编号为0、1的两个人循环报数时,编号为0的人报的数为0和2,当报到2(M–1)时,编号0出列,最后剩下编号为1的人,所以编号为1的人最后出列。

                                  编号:  0    1

                                报数:0,2   1

 

根据上面的推导过程,可以很容易推导出,当N=3时的公式:

                                 F(2)=[F(1)+M]%3

 

同理,也可以推导出参与人数为N时,最后出列人员编号的公式:

 

                                F(N)=[F(N-1)+M]%N

 

 

 

其实,这就是一个递推公式,公式包含以下两个式子:

                                         F(1)=0

                       F(N)=[F(N-1)+M]%n (N>1)

 

 

 

有了这个递推公式,再来设计程序就很简单了,可以用递归的方法来设计程序,具体代码如下:

/*****************************************************
copyright (C), 2014-2015, Lighting Studio. Co.,     Ltd. 
File name:
Author:Jerey_Jobs    Version:0.1    Date: 
Description:
Funcion List: 
*****************************************************/

#include <stdio.h>
int main(void)
{
    int n,m,i,s = 0 ;
    printf("输入参与人数N和出列位置M的值\n");
    scanf("%d%d",&n,&m);
    for(i = 2;i <=n;i++)
    {
        s=(s+m)%i;
    }
    printf("最后出列的人最初位置是%d\n",s+1);
    return 1;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_43613919/article/details/88068569

智能推荐

java.lang.ClassNotFoundException:如何解决-程序员宅基地

文章浏览阅读7.2w次,点赞10次,收藏41次。本文适用于当前面临java.lang.ClassNotFoundException挑战的Java初学者。 它将为您提供此常见Java异常的概述,这是一个示例Java程序,可支持您的学习过程和解决策略。 如果您对与更高级的类加载器相关的问题感兴趣,我建议您复习有关java.lang.NoClassDefFoundError的文章系列,因为这些Java异常密切相关。 java.lang..._java.lang.classnotfoundexception:

串口通信数据帧_一帧数据-程序员宅基地

文章浏览阅读1.2k次,点赞9次,收藏17次。不同的设备间建立连接往往需要通信,而串口通信是十分常用的一种。UART串口通信需要两根线来实现,一根用于串口发送,另外一更用于串口接收。UART串口发送或者接收过程中一帧数据包括1位起始位、8位数据位、1位停止位,为了提高数据的可靠性可以在停止位前加上1位奇偶校验位。串口通信虽然十分简单,但是在不同设备间发送的数据往往不止1个字节,往往需要多个字节组成的数据包。当我们按照数据包发送时我们需要考虑到以及,因此我们可以采用定义数据帧的方式解决上述两个问题。_一帧数据

代码编辑快捷键使用说明_改代码快捷键-程序员宅基地

文章浏览阅读1.4k次。1、Ctrl+←或→ :跳过(左边或右边)一个光标相邻的单词或词组(标点符号相当于一个单词)。点击前光标位置:点击后光标位置:2、Shift+←或→:选中(左边或右边)一个光标相邻的字符。点击前显示:点击后显示: 3、Shift+Ctrl+←或→:选中(左边或右边)一个光标相邻的单词或词组(标点符号相当于一个单词)。点击前显示:点击后显示:4、Home/End:光标定位到当前行的行头/行尾。点击前:点击Home后:点击End后:5、Ctrl+Home/End:从光标所在位置直接回到当前文件开头/结尾。点击前_改代码快捷键

【课上笔记】第七章 树与森林_树和森林的区别-程序员宅基地

树是一个有n个有限数据元素的集合,其中有一个根节点,并且每个节点可以有多个子节点。树的深度与查找有关,可通过改进合并算法来减少树的深度,提高算法效率。

【信贷风控30分钟精通39】风控策略体系搭建2-程序员宅基地

文章浏览阅读938次,点赞23次,收藏21次。反欺诈策略是为防范恶意客户采取欺诈行为谋取利益而制订的策略,目的是通过对欺诈行为的识别,遏制欺诈风险,为金融机构止损。根据欺诈的不同维度,欺诈的分类目前,应对欺诈风险的有效措施包括反欺诈规则和反欺诈模型。

yum安装及配置_安装yum-程序员宅基地

文章浏览阅读10w+次,点赞40次,收藏332次。yum是用来管理rpm的,就跟maven管理jar包相似。yum源(库)分为本地库、网络库。首先要配置yum源,可支持多个源。先查看一下挂载情况:df -h这里我们要更换光盘,并挂载:mount /dev/cdrom /mnt(如果不能成功挂载,点击一下连接即可)之后再次使用 df -h命令,就能查看到光盘的内容。下面我们cd到 /mnt下查看一下:首先关注一下Pa..._安装yum

随便推点

看不见的“网” ,一文读懂阿里云基础设施网络_阿里云网络基线理解-程序员宅基地

文章浏览阅读553次。编者按:在这个万物智联的时代,无论是在线网络购物,还是网络强国、数字中国建设,都离不开一张“看不见的网”——基础设施网络。2009年,首届双11每秒交易订单创建峰值400;2021年,双11每秒交易订单创建峰值58.3万,12年交易数字量猛增的背后,是阿里云在庞大分布式系统上计算和IO能力的飞跃,更离不开阿里云基础设施底层网络技术的支撑。图|阿里云全球基础设施网络系统作为阿里云基础设施的重要组成部分,阿里云基础设施网络团队负责整个阿里云全球基础设施网络,包括大规模高性能数据中心网络,全球数据中心互联_阿里云网络基线理解

TCP/UDP常见端口参考_怎么查看端口映射的是tcp还是udp-程序员宅基地

文章浏览阅读1.7k次。端口列表一览端口号码 / 层 名称 注释 1 tcpmux TCP 端口服务多路复用 5 rje 远程作业入口 7 echo Echo 服务 9 discard 用于连接测试的空服务 11 systat 用于列举连接了的端口的系统状态 13 daytime 给请求主机发送日期和时间 17 qotd 给连接了的主机发送每日格言 18 msp 消息发送协议 19 _怎么查看端口映射的是tcp还是udp

android JSBridge 漏洞挖掘_adnroid jsbridge 不安全的资源引用-程序员宅基地

文章浏览阅读825次。一、概述1. JSBridge介绍什么是JSBridge主要是给 JavaScript 提供调用 Native 功能的接口,让混合开发中的前端部分可以方便地使用 Native 的功能(例如:地址位置、摄像头)。而且 JSBridge 的功能不止调用 Native 功能这么简单宽泛。实际上,JSBridge 就像其名称中的Bridge的意义一样,是 Native 和非 Native 之间的桥梁,它的核心是构建 Native 和非 Native 间消息通信的通道,而且这个通信的通道是双向的。双向通信的通_adnroid jsbridge 不安全的资源引用

OpenCV+Mediapipe+UDP+Unity挥手电子书翻页_unity opencv 虚拟翻书-程序员宅基地

文章浏览阅读2k次,点赞13次,收藏43次。OpenCV+Mediapipe+UDP+Unity挥手翻页_unity opencv 虚拟翻书

推荐文章

热门文章

相关标签