`

约瑟夫环问题

    博客分类:
  • C
阅读更多
约瑟夫环问题

  约瑟夫环(Josephus)问题是由古罗马的史学家约瑟夫(Josephus)提出的,他参加并记录了公元66—70年犹太人反抗罗马的起义。约瑟夫作为一个将军,设法守住了裘达伯特城达47天之久,在城市沦陷之后,他和40名死硬的将士在附近的一个洞穴中避难。在那里,这些叛乱者表决说“要投降毋宁死”。于是,约瑟夫建议每个人轮流杀死他旁边的人,而这个顺序是由抽签决定的。约瑟夫有预谋地抓到了最后一签,并且,作为洞穴中的两个幸存者之一,他说服了他原先的牺牲品一起投降了罗马。
  约瑟夫环问题的具体描述是:设有编号为1,2,……,n的n(n>0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,……,如此下去,直到所有人全部出圈为止。当任意给定n和m后,设计算法求n个人出圈的次序。 



#include <stdio.h>
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 ("The winner is %d\n", s+1);
}/*运用了一点数学策略 N=8 M=3 幸存为7 ;少于3的时候还可以数,因为为一个环;从他的下一个人起重新报数*/
5
2
分享到:
评论
3 楼 lb11 2009-07-27  
2 楼 chenchuxin 2008-03-18  
????难看懂,什么时候自己写个无节点的循环链表,再不断删除
1 楼 chenchuxin 2008-03-18  
约瑟夫环
是一个数学的应用问题:

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

   这个就是约瑟夫环问题的实际场景,有一种是要通过输入n,m,k三个正整数,来求出列的序列。这个问题采用的是典型的循环链表的数据结构,就是将一个链表的尾元素指针指向队首元素。 p->link=head

   解决问题的核心步骤:
       1.建立一个具有n个链结点,无头结点的循环链表
       2.确定第1个报数人的位置
       3.不断地从链表中删除链结点,直到链表为空

void JOSEPHUS(int n,int k,int m) //n为总人数,k为第一个开始报数的人,m为出列者喊到的数
{
    /* p为当前结点  r为辅助结点,指向p的前驱结点  list为头节点*/
    LinkList p,r,list;

    /*建立循环链表*/
    for(int i=0,i<n,i++)
    {
        p=(LinkList)malloc(sizeof(LNode));
        p->data=i;
        if(list==NULL)
            list=p;
        else
            r->link=p;
        r=p;
    }
    p>link=list; /*使链表循环起来*/
    p=list; /*使p指向头节点*/

    /*把当前指针移动到第一个报数的人*/
    for(i=0;i<k;i++)
    {
        r=p;
        p=p->link;
    }

    /*循环地删除队列结点*/
    while(p->link!=p)
    {
        for(i=0;i<m;i++)
        {
            r=p;
            p=p->link;
        }
        r->link=p->link;
        printf("被删除的元素:%4d ",p->data);
        free(p);
        p=r->link;
    }
    printf("\n最后被删除的元素是:%4d",P->data);
}

证明:
Josephus(约瑟夫)问题的数学方法(转)约瑟夫 (转)

     无论是用链表实现还是用数组实现都有一个共同点:要模拟整个
游戏过程,不仅程序写起来比较烦,而且时间复杂度高达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个人玩游戏报m退出最后胜利者的编号,最后的结果自然
是f[n]
递推公式
f[1]=0;
f=(f[i-1]+m)%i;   (i>1)
有了这个公式,我们要做的就是从1-n顺序算出f的数值,最后结
果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1
由于是逐级递推,不需要保存每个f,程序也是异常简单:
#include <stdio.h>
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 ("The winner is %d\n", s+1);
}
这个算法的时间复杂度为O(n),相对于模拟算法已经有了很大的提高
。算n,m等于一百万,一千万的情况不是问题了。可见,适当地运用
数学策略,不仅可以让编程变得简单,而且往往会成倍地提高算法执
行效率。

相关推荐

    循环队列和约瑟夫环问题

    循环队列和约瑟夫环问题 循环队列是一种特殊的队列结构,它的特点是队列的末尾元素连接着队列的开头元素,形成一个环形结构。这种数据结构可以用来解决约瑟夫环问题。 约瑟夫环问题是一个经典的问题,它是由古罗马...

    敢死队问题课程设计(约瑟夫环问题的应用)

    【敢死队问题(约瑟夫环问题的应用)】是一个经典的计算机科学问题,它涉及到数据结构和算法的设计。在这个问题中,M个敢死队员通过循环计数的方式决定执行任务的顺序,每数到5的人将执行任务并退出,直至只剩下一个...

    用循环链表实现约瑟夫环问题

    使用c语言中的循环链表及结构体实现约瑟夫环问题

    数据结构约瑟夫环问题

    数据结构中的约瑟夫环问题是一种经典的编程问题,它涉及到链表这一数据结构的应用。在本文中,我们将深入探讨约瑟夫环问题的背景、原理以及如何使用链表来求解这一问题,同时分析给定代码的具体实现细节。 ### ...

    约瑟夫环问题算法描述和程序实现(C#)

    约瑟夫环问题,也称为约瑟夫环序列或约瑟夫问题,是一个著名的理论问题,源自古罗马历史上的一个故事。在这个问题中,人们围成一个圈,并按照一定的规则依次淘汰,最后留下来的人被称为“幸存者”。具体规则是:从...

    约瑟夫环问题用C++代码实现

    约瑟夫环问题,也称为约瑟夫问题,是一个经典的理论问题,源于古罗马时期的传说。问题描述了一群人围坐成一个圆圈,按照一定的规则进行报数,每数到特定数字的人会被排除,直到所有人都被排除。在这个场景中,我们...

    c++多种方法解决约瑟夫环问题

    多种方法解决约瑟夫环问题,1.顺序表2.循环链表3.循环队列4.普通一位数组

    约瑟夫环问题(C++)

    约瑟夫环问题,也被称为约瑟夫环序列或约瑟夫问题,是一个著名的理论问题,源自古罗马历史上的一个故事。在这个问题中,人们站成一个圈,并按顺时针方向编号。从某个人开始,每隔特定的人数,这个人就会被排除出圈,...

    详细介绍约瑟夫环问题解析.docx

    约瑟夫环问题解析 约瑟夫环问题是计算机科学和数学中一个著名的问题,它是指在一个圆圈中的人按照一定的规则依次出列的问题。该问题的解析报告将从以下几个方面进行讲解: 一、问题描述 约瑟夫环问题可以用以下...

    约瑟夫环问题的编程实现

    约瑟夫环问题,也称为约瑟夫环序列或约瑟夫问题,是一个著名的理论问题,源自古罗马历史的一个故事。在数学和计算机科学中,它通常被用来演示各种算法,特别是循环移位和递归算法。这个问题描述如下:假设有一群人围...

    用C语言实现约瑟夫环问题

    《C语言实现约瑟夫环问题详解》 约瑟夫环问题,又称约瑟夫环序列,是一个著名的理论问题,源自古罗马的一个传说。在这个问题中,人们围成一个圈,按照一定的规则逐个淘汰,直到剩下最后一个人为止。这个问题在...

    约瑟夫环问题用循环队列解决

    用循环队列解决约瑟夫环问题减少用顺序表在出对是循环移动带来的空间复杂度

    1模拟轮盘抽奖游戏2模拟报数游戏(约瑟夫环问题)_抽奖轮盘_模拟报数游戏_模拟轮盘抽奖游戏_游戏_用python实现_

    在本项目中,我们将探讨如何使用Python编程语言来实现两种有趣的数学和计算机科学相关的游戏:模拟轮盘抽奖游戏和模拟报数游戏,也称为约瑟夫环问题。这两个游戏不仅有趣,而且能帮助我们理解循环、列表操作以及算法...

    约瑟夫环问题,C语言编写

    数据结构中的约瑟夫环问题 C语言编写,已经测试通过

    约瑟夫环问题的源代码(c++)

    约瑟夫环问题的源代码分析 约瑟夫环问题是计算机科学中的一种经典问题,描述的是10个小孩围坐在一圈,并给他们依次编号,指定从第s个小孩开始报数(从1~n报数),报到n的小孩出列,然后依次重复下去,直到所有的...

    C语言编写的关于约瑟夫环问题的程序

    标题中的“C语言编写的关于约瑟夫环问题的程序”指的是使用C编程语言实现的一个经典算法问题——约瑟夫环(Josephus Problem)。约瑟夫环问题是一个理论上的问题,通常在计算机科学和数学中被用作示例,以讨论和解决...

    数据结构实验报告--约瑟夫环问题

    实验报告的主题是“约瑟夫环问题”,这是一个经典的数据结构问题,源于数学家约瑟夫·弗朗西斯·里斯提出的假设情景。该问题描述了一群人围成一个圈,从某个人开始按顺时针方向依次报数,每当数到特定数值的人会被...

Global site tag (gtag.js) - Google Analytics