约瑟夫问题

线性表应用:约瑟夫问题(猴子选大王)(循环链表,数组,递归)

喜你入骨 提交于 2020-03-14 12:41:16
1 描述:一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。 2 如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王? 3 //用循环链表 4 #include<stdio.h> 5 #include<stdlib.h> 6 7 typedef struct node 8 { 9 int data; 10 struct node *next; 11 }node; 12 13 node *create(int n) 14 { 15 node *head; 16 node *p = NULL; 17 head = (node *)malloc(sizeof(node)); 18 p = head; //p为指向当前结点的指针 19 node *s; 20 int i = 1; 21 22 if(n != 0) 23 { 24 while(i <= n) 25 { 26 s = (node *)malloc(sizeof(node)); //临时的结点 27 s->data = i++; //第一个结点的值为1 第二个结点的值为2 先给值i才++ 28 p->next = s; //头结点的指针域指向第一个结点 29 p =

循环单链表,解决约瑟夫问题

℡╲_俬逩灬. 提交于 2020-03-01 14:23:47
约瑟夫问题: 编号为1~N的N个人按顺时针方向围坐一圈,每人持有一个密码(正整数),开始任选一个正整数作为报数上限值M,从第1个人按顺时针方向自1开始顺序报数,报到M时停止报数。报M的人出列,将他的密码作为新的M值,从他顺时针方向上的下一个人开始从1报数,如此下去,直至所有人全部出列为止。 解析: 显然当有人退出圆圈后,报数的工作要从下一个人开始继续,而剩下的人仍然围成一个圆圈,因此可以使用循环单链表。退出圆圈的工作对应着表中节点的删除操作,对于这种删除操作频繁的情况,选用效率较高的链表结构,为了程序指针每次都指向一个具体的代表一个人的节点而不需要判断,链表不带头节点。因此,对于所有人围成的圆圈所对应的数据结构采用一个不带头节点的循环链表来描述。 1 #include "stdafx.h" 2 #include <iostream> 3 #include "string.h" 4 using namespace std; 5 6 typedef struct node 7 { 8 int data; 9 node *next; 10 }node; 11 12 node *create(int n) //创建节点数量为n的单向循环链表 13 { 14 node *pRet = NULL; 15 if(n != 0) 16 { 17 int n_idx = 1; 18 node *p

1.递归问题之约瑟夫问题

↘锁芯ラ 提交于 2020-02-26 02:32:06
文章目录 约瑟夫问题 问题描述 解决思路 扩展思考 约瑟夫问题 问题描述 从围成标记有记号1到n的圆圈的n个人开始,每隔一个人删去一个人,知道只剩一个人。例如n=10的起始图形: 消去的顺序是2,4,6,8,10,3,7,1,9,于是5幸存了下来。问题:确定幸存的号码 J ( n ) J(n) J ( n ) 。 解决思路 从简单情形出发,找规律 n n n 1 2 3 4 5 6 J ( n ) J(n) J ( n ) 1 1 3 1 3 5 发现并没有明显规律。 发现 J ( 2 n ) J(2n) J ( 2 n ) 与 J ( n ) J(n) J ( n ) 的关系: J(20)时,删去2,4,6…2n后,剩下的情形和J(n)相似,个数与顺序相同就表明幸运号码在相同的地方,不同之处就是,每项的数字大小,容易得到: J ( 2 n ) = 2 J ( n ) − 1 J(2n)=2J(n)-1 J ( 2 n ) = 2 J ( n ) − 1 类似的发现 J ( 2 n + 1 ) = 2 J ( n ) + 1 J(2n+1)=2J(n)+1 J ( 2 n + 1 ) = 2 J ( n ) + 1 由以上递推式可以列表: n n n 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 … J ( n ) J(n) J ( n ) 1 1

单向环形链表 约瑟夫问题

孤者浪人 提交于 2020-02-19 09:08:56
Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。 链表如下图 数2下 自己也要数 所以只会移动1次 构建链表,遍历链表 分析图 first.next = 2 3.next = first 让最后一个元素的next指向first 首先 创建一个环形链表 // 创建一个first节点,当前没有编号 private Boy first = null; // 添加小孩节点,构建成一个环形的链表 public void addBoy(int nums) { // nums 做一个数据校验 if (nums < 1) { System.out.println("nums的值不正确"); return; } Boy curBoy = null; // 辅助指针,帮助构建环形链表 // 使用for来创建我们的环形链表 for (int i = 1; i <= nums; i++) { // 根据编号,创建小孩节点 Boy boy = new Boy(i); // 如果是第一个小孩 第一次 if (i == 1) { first = boy; //这是头指针 把第一个的赋值给first //不太理解

约瑟夫问题(C++单向链表解法)

安稳与你 提交于 2020-02-05 18:47:23
【问题描述】 n 个人(编号从1~n)围成一圈,从第 k 个人开始数数,数到 m 的人出圈,然后继续从未出列的下一个人开始数数,数到 m 的人出圈,重复上述过程,直到圈中仅剩下一人。 【输入形式】 输入为一行三个正整数,n、k、m。 【输出形式】 输出为一个正整数,表示最后剩下的人的编号。 【样例输入】 100 1 5 【样例输出】 47 【示例代码】 (可对比数七小游戏) # include <iostream> using namespace std ; class person { private : int no ; /* 人的编号 */ person * next ; /* 指向相邻的下一个人 */ public : person ( int num ) { no = num ; next = NULL ; } void setNext ( person * p ) { next = p ; } int getNo ( ) { return no ; } person * getNext ( ) { return next ; } } ; class cycle { private : person * start ; /* 开始数数的位置 */ int out ; /* 数到几出列 */ int inQueue ; /* 队伍中现有人数 */ public :

P1996 约瑟夫问题(C++_模拟)

坚强是说给别人听的谎言 提交于 2020-02-01 14:21:10
题目背景 约瑟夫是一个无聊的人!!! 题目描述 n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……依次类推,直到所有的人都出圈,请输出依次出圈人的编号. 输入格式 n m 输出格式 出圈的编号 输入输出样例 输入 #1 10 3 输出 #1 3 6 9 2 7 1 8 5 10 4 说明/提示 m,n≤100 思路 把走过的点标记一遍,只有未标记过的点才算数,如果所有点都标记过了,那么程序运行结束。(dbq, 让这种水题拉低了我的博客整体题解难度,不过也体验了一把神犇切题的快感~) 源码 # include <bits/stdc++.h> using namespace std ; int n , m , sum = 0 ; int a [ 100 ] , b [ 100 ] ; bool judge ( ) { for ( int i = 0 ; i < n ; i ++ ) if ( b [ i ] == 0 ) return 0 ; return 1 ; } int main ( ) { cin >> n >> m ; memset ( b , 0 , sizeof ( b ) ) ; for ( int i = 0 ; ! judge ( ) ; i ++ ) { if ( i == n ) i = 0

#2019120700020 约瑟夫问题七问

为君一笑 提交于 2020-01-27 06:01:18
1.基本约瑟夫问题 题目描述 \(n\) 个人( \(n\le 100\) )围成一圈,从第一个人开始报数,数到 \(m\) 的人出列,再由下一个人重新从 \(1\) 开始报数,数到 \(m\) 的人再出圈,……依次类推,直到所有的人都出圈,请输出依次出圈人的编号. 输入格式 \(n m\) 输出格式 出圈的编号 样例输入 10 3 样例输出 3 6 9 2 7 1 8 5 10 4 说明 \(m, n \le 100\) 2 题意描述 已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。 输入 \(n,k,m\) 输出 按顺序输出出圈人的编号 样例输入 9 1 5 样例输出 5 1 7 4 3 6 9 2 8 3 约瑟夫问题是个有名的问题: \(N\) 个人围成一圈,从第一个开始报数,第 \(M\) 个将被杀掉,最后剩下一个,其余人都将被杀掉。例如 \(N=6\) , \(M=5\) ,被杀掉的人的序号为5,4,6,2,3。最后剩下1号。 假定在圈子里前 \(K\) 个为好人,后 \(K\) 个为坏人,你的任务是确定这样的最小 \(M\) ,使得所有的坏人在第一个好人之前被杀掉。 4 \(n\) 个人排成一圈。从某个人开始

单向环形链表及约瑟夫问题的java实现

时光毁灭记忆、已成空白 提交于 2020-01-21 03:18:59
约瑟夫问题(Josephu问题)也称为“丢手帕问题”。 问题描述: 设编号为1、2、3、4......的n个小朋友围成一圈,约定编号为 k 的小朋友从 1 开始报数,轮流数到 m 的小朋友出列。接着出列小朋友的下一位又从1开始报数,轮流数到 m 的小朋友出列,以此类推,直到所有小朋友都出列为止,由此产生一个出列编号的序列。 n = 5 表示有 5 个小朋友 ; k = 1 表示从第 1 个小朋友开始报数 ; m = 2 表示每次数 2 下。 本问题由于需要不断地删除节点,同时循环报数,因而用到单向环形链表。 首先创建一个节点类Boy : class Boy{ private int no ; //小孩的编号 private Boy next ; //指向下一个节点,默认为null public Boy(int no){ this.no = no ; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public Boy getNext() { return next; } public void setNext(Boy next) { this.next = next; } /* * 之所以要设置这几个构造方法,是因为Boy的几个基本属性都是private类型 */ }

5. 环形链表实现约瑟夫问题

大城市里の小女人 提交于 2020-01-11 17:15:22
一、概念 1. 环形链表 环形链表是另一种形式的链式存贮结构。它的特点是表中最后一个结点的指针域指向第一个结点,整个链表形成一个环。 2. 约瑟夫问题 设编号为1,2,…,n 的n个人围坐一圈,约定编号为 k (1 ≤ k ≤ n) 的人从1开始报数,数到m的那个人出列,出列的人的下一位又从1开始报数,数到m的那个人又出列,以此类推,直到所有人都出列为止,由此产生一个出队编号的队列。 二、环形链表和约瑟夫问题的实现 1. 环形链表的实现 思路: 先定义一个 first 变量初始值为空,目的是让 first 指向环形链表的第一个结点; 为保证first变量不能移动,所以应该定义一个辅助变量 curr 来帮助后续的结点加入构成环形链表,curr的初始值也为null; 在加入第一个结点时,就让 first 指向该节点,first的next指向自己,curr此时处于第一个结点的位置, 即first = boy,first.next = first,curr = first,从而形成一个环; 从加入第二个节点开始,就让 curr 变量 next 指向这个加入的新结点,新结点的 next 指向第一个结点, 即curr.next = newBoy,newBoy.next = first,curr = boy; 后面当我们每创建一个新结点,就把该结点加入到已有的环形链表中即可。 代码实现: /**

约瑟夫问题

孤街醉人 提交于 2020-01-05 03:57:37
约瑟夫问题的来历 据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。 17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。 问题分析与算法设计 约瑟夫问题并不难,但求解的方法很多;题目的变化形式也很多。这里给出一种实现方法。 题目中30个人围成一圈,因而启发我们用一个循环链表来表示。可以使用结构数组来构成一个循环链。结构中有两个成员,其一为指向下一个人的指针,以构成环形的链;其二为该人是否被扔下海的标记,为1表示还在船上。从第一个人开始对还未扔下海的人进行计数,每数到9时,将结构中的标记改为0