约瑟夫环问题,一道经典的数据结构题目

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。

一般我们采用一个循环队列来模拟约瑟夫环的求解过程,但是如果n比较大的时候,采用模拟的方式求解,需要大量的时间来模拟退出的过程,而且由于需要占用大量的内存空间来模拟队列中的n个人,并不是一个很好的解法。

在大部分情况下,我们仅仅需要知道最后那个人的编号,而不是要来模拟一个这样的过程,在这种情况下,可以考虑是否存在着一种数学公式能够直接求出最后那个人的编号。

我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):

我们先看第一个人出列后的情况,显而易见,第一个出列的人的编号一定是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-1

可以看出,这就是原问题中把n替换成n-1的情况,假设我们已经求出来在这种情况下(即n-1个数字时)最后胜利的那个人的编号是n-1中的x,那个倒推回去的n个数字时那个人的编号就是我们要求的答案,显而易见,这个编号应该是(x+k)%n,而k=m%n,所以这个编号为(x+m)%n.

那么如何知道n-1个人下面的这个x呢,yes,就是n-2个人情况下得到的x’倒推回去,那么如何知道n-2情况下的x’呢,当然是求n-3个人,这就是一个递归的过程

f(1) = 0(f(1)就是现在还剩下1个人,那么无论m为几,这个人总会出列,因此f(1)=0)

f(n) = (f(n-1)+m)%n

那么我们要求f(n),就从f(1)倒推回去即可。

#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);

}

转载请注明:约瑟夫环问题,一道经典的数据结构题目

原文地址:https://www.cnblogs.com/whiterock/p/8158812.html

时间: 2024-10-02 04:54:33

约瑟夫环问题,一道经典的数据结构题目的相关文章

约瑟夫环-公式递推法

约瑟夫问题 约瑟夫问题是个著名的问题:N个人围成一圈,第一个人从1开始报数,报M的将被杀掉,下一个人接着从1开始报.如此反复,最后剩下一个,求最后的胜利者. 例如只有三个人,把他们叫做A.B.C,他们围成一圈,从A开始报数,假设报2的人被杀掉. 首先A开始报数,他报1.侥幸逃过一劫. 然后轮到B报数,他报2.非常惨,他被杀了 C接着从1开始报数 接着轮到A报数,他报2.也被杀死了. 最终胜利者是C 解决方案 普通解法 刚学数据结构的时候,我们可能用链表的方法去模拟这个过程,N个人看作是N个链表节

【算法题目】约瑟夫环问题

题目来源:<剑指offer>面试题45 题目:0,1,...,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字.求出这个圆圈里剩下的最后一个数字. 解法一:经典解法,用环形链表模拟圆圈.这种方法每删除一个数字需要m步运算,总共有n个数字,因此总的时间复杂度是O(mn).同时这种思路还需要一个辅助链表来模拟圆圈,其空间复杂度是O(n). int LastRemaining(unsigned int n, unsigned int m) { if (n < 1 ||

约瑟夫环(N个人围桌,C语言,数据结构)

约瑟夫环问题(C语言.数据结构版) 一.问题描述 N个人围城一桌(首位相连),约定从1报数,报到数为k的人出局,然后下一位又从1开始报,以此类推.最后留下的人获胜.(有很多类似问题,如猴子选代王等等,解法都一样) 二.思路分析 (1)可将人的顺序简单编号,从1到N: (2)构造一个循环链表,可以解决首位相连的问题,同时如果将人的编号改为人名或者其他比较方便 (3)将人的编号插入到结构体的Data域: (4)遍历人的编号,输出参与的人的编号: (5)开始报数,从头报数,报到k的人出局(删除次结点)

经典例题|约瑟夫环多方法解决

本文章将用循环链表.数组.递归以及循环方法对约瑟夫环问题进行讲解.其中链表法和数组法会对过程进行模拟,递归和循环将对约瑟夫环问题进行数学剖析. 问题描述 n个人围成圈,依次编号为1.2.3.....n,从1号开始依次报数,当报到m时,报m的人退出,下一个人重新从1报起,当报到m时,报m的人退出,如此循环下去,问最后剩下的那个人的编号是多少? 链表法 建立一个循环链表,节点的数值部分存储整数1至n,将尾部节点链接到第一个节点,每次遍历m-2步,把第m-1个节的指针域指向的节点数据打印出来,然后将m

小朋友学数据结构(1):约瑟夫环的链表解法、数组解法和数学公式解法

约瑟夫环的链表解法.数组解法和数学公式解法 约瑟夫环(Josephus)问题是由古罗马的史学家约瑟夫(Josephus)提出的,他参加并记录了公元66-70年犹太人反抗罗马的起义.约瑟夫作为一个将军,设法守住了裘达伯特城达47天之久,在城市沦陷之后,他和40名死硬的将士在附近的一个洞穴中避难.在那里,这些叛乱者表决说"要投降毋宁死".于是,约瑟夫建议每个人轮流杀死他旁边的人,而这个顺序是由抽签决定的.约瑟夫有预谋地抓到了最后一签,并且,作为洞穴中的两个幸存者之一,他说服了他原先的牺牲品

【数据结构】1-2 约瑟夫环问题

这里放出两种不同的代码,一个是老师给的(较为复杂),还有一个是自己写的. 自己写的: #include<iostream> using namespace std; struct Node { int data; //数据单元 Node *link; //指向下一个结点 }; class Josephus { private: Node *head, *current; //head是头结点,current指向当前结点 int sum;//存储链表中元素的个数 public: Josephus

Java数据结构之单向环形链表(解决Josephu约瑟夫环问题)

1.Josephu(约瑟夫.约瑟夫环)问题: 设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列. 提示: 用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法

Roman Roulette(约瑟夫环模拟)

Roman Roulette Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 286    Accepted Submission(s): 105 Problem Description The historian Flavius Josephus relates how, in the Romano-Jewish conflict of

B. Counting-out Rhyme(约瑟夫环)

Description n children are standing in a circle and playing the counting-out game. Children are numbered clockwise from 1 to n. In the beginning, the first child is considered the leader. The game is played in k steps. In the i-th step the leader cou