循环链表实例(猴子选大王)

合集下载

monkey

monkey

课程设计说明书
2.1.4 2.1.4.创建单向基本链表基本算法
创建循环单链表函数 采用头插法创建单向循环链表 Status CreateList(elemtype m) { List head, p; head = (List)malloc(sizeof(struct Node)); //*为头指针申请两个空间*// head->next = head; //*一共有 m 个猴子,所以建立含有 m 个结点的单向循环链表*// for (i = 1; i < m; ++i) { p = (List)malloc(sizeof(struct Node)); / /*为结点申请两个空间*// p->next = head->next; head->next = p; }//*利用 for 循环实现链表的创建*// p = head; //*将指针 p 指向表头*//
No.8
沈阳大学
课程设计说明书
2.1.6 2.1.6 主函数方案设计
No.9
在主函数中首先设计程序的登陆界面信息,用户可以根据界面的提示,完成猴子选大 王的基本操作过程,为了使操作更加人性化,使输入猴子的数目 m 和决定要淘汰的猴子 编号 n,通过键盘输入,若输入错误是(m<n),界面将用英文提示输入错误请重新输入, ,若输入正确,程序将显示运行后的结果,显示最后猴子大王的编号,并显示被淘汰猴子 的编号,程序运行完毕。 在主函数中,在用户输入结束后,分别调用创建链表函数 CreateList(elemtype m)和猴 子选大王参数 LinkedList(elemtype num_monkey, elemtype number),经过一些列的运 算,最后得出猴子大王的编号,及其被淘汰的猴子的编号,以上即为函数的基本功能的 实现过程。

猴子选大王

猴子选大王

[题目]第1.1猴子选大王问题一:实验内容:M只猴子要选大王,选举办法如下:所有猴子按1,2……n编号围成一圈,从第一号开始顺序1,2……m,凡是报m号的退出圈外,如此循环报数直到圈内只剩一只猴子时这只猴子就是大王。

二:实验要求:利用单向循环链表模拟此过程,输出选出的大王编号。

三:程序的设计思想:(1)问题分析:“猴子选大王”问题是约瑟夫环问题的一个特例。

由于本题目的数据元素个数不可知,所以可使用链表来动态的分配内存空间。

而该问题又是一个不断的循环问题所以用循环链表来实现。

(2)总体设计:首先生成一个空链表,并给n个结点分配空间,让单链表的表尾指针指向头结点则生成一个带有n个结点的循环单链表。

再给每只猴子建立顺序的编号。

现从第一个结点开始报数,依次顺序查找出报数为m的待出列的结点(猴子)通过q->next=p->next删除该结点后继续运行否则让q成为p的前驱指针。

最后当p->next==p时停止运行,得到p所指向的结点即为猴子选出大王的编号。

四:提供测试结果:定义 n=8, m=3,测试结果如下:对猴子进行编号!1号猴子:12号猴子:23号猴子:34号猴子:45号猴子:56号猴子:67号猴子:78号猴子:82号猴子报:2 3号猴子报:3 3号猴被淘汰4号猴子报:1 5号猴子报:2 6号猴子报:3 6号猴被淘汰7号猴子报:1 8号猴子报:2 1号猴子报:3 1号猴被淘汰2号猴子报:1 4号猴子报:2 5号猴子报:3 5号猴被淘汰7号猴子报:1 8号猴子报:2 2号猴子报:3 2号猴被淘汰4号猴子报:1 7号猴子报:2 8号猴子报:3 8号猴被淘汰7号猴子报:24号猴子报:34号猴被淘汰7号猴子报:1胜出:7号猴子Press any key to continue五:程序源代码#include <stdio.h>#include <stdlib.h>#define n 8#define m 3typedef struct monkey{int num;struct monkey *next;} Monkey;int main(){Monkey *p,*head,*q;int i;head=p=q=malloc(sizeof(Monkey));//建立头指针 for(i=1;i<n;i++) //给n个结点分配空间{p=malloc(sizeof(Monkey));q=p;}q->next=head; //建立循环链表p=head;printf("对猴子进行编号!\n");for(i=1;i<=n;i++) //给n只猴子分别建立顺序编号{p->num=i;printf("%d号猴子:%d\n",p->num,p->num);p=p->next;}i=0; //初始化p=head;while(1){i++;printf("%d号猴子报:%d\n",p->num,i);if(p->next==p) break; //判断还剩下最后一个结点时停止运行 if(i==m) //报道m的猴子淘汰{i=0;printf("%d号猴被淘汰\n",p->num);q->next=p->next;continue;}else{if(i==m-1) q=p;p=p->next;}}printf("胜出:%d号猴子",p->num); }。

C语言 猴子选大王

C语言 猴子选大王

* 用数组做的,循环遍历数组,增加了一些注释,希望你能看懂。

*/#include<stdio.h>#include<stdlib.h>#include<string.h>void SelectKing(int MonkeyNum, int CallNum);void main(){int MonkeyNum;int CallNum;/* 输入猴子的个数*/printf("Monkey Num = ");scanf("%d", &MonkeyNum);/* 输入M的值*/printf("Call Num = ");scanf("%d", &CallNum);SelectKing(MonkeyNum, CallNum);}void SelectKing(int MonkeyNum, int CallNum){int *Monkeys; // 申请一个数组,表示所有的猴子;int counter = 0; //计数,当计数为猴子个数时表示选到最后一个猴子了;int position = 0; // 位置,数组的下标,轮流遍历数组进行报数;int token = 0; // 令牌,将报数时数到M的猴子砍掉;// 申请猴子个数大小的数组,把桌子摆上。

Monkeys = (int *)malloc(sizeof(int)* MonkeyNum);if (NULL == Monkeys){printf("So many monkeys, system error.\n");return;}// 将数组的所有内容初始化为0,被砍掉的猴子设置为1memset(Monkeys, 0, sizeof(int)*MonkeyNum);// 循环,直到选中大王while(counter != MonkeyNum){// 如果这个位置的猴子之前没有砍掉,那么报数有效if (Monkeys[position] == 0){token++; // 成功报数一个,令牌+1,继续报数直到等于M// 如果报数到M,那么将这个猴子砍去if (token == CallNum){Monkeys[position] = 1; // 设置为1,表示砍去counter++; // 计数增加token = 0; // 设置为0,下次重新报数// 如果是最后一个猴子,把它的位置打印,这个就是大王了if (counter == MonkeyNum){printf("The king is the %d monkey.\n", position+1);}}}// 下一个猴子报数position = (position + 1)%MonkeyNum;}// 释放内存,开头为所有猴子创建的桌子free(Monkeys);return;}。

“约瑟夫”问题及若干变种

“约瑟夫”问题及若干变种

“约瑟夫”问题及若⼲变种“约瑟夫”问题及若⼲变种例1、约瑟夫问题(Josephus)[问题描述]M只猴⼦要选⼤王,选举办法如下:所有猴⼦按1…M编号围坐⼀圈,从第1号开始按顺序1,2,…,N报数,凡报到N的猴⼦退出到圈外,再从下⼀个猴⼦开始继续1~ N报数,如此循环,直到圈内只剩下⼀只猴⼦时,这只猴⼦就是⼤王。

M和N由键盘输⼊,1≤N,M≤10000,打印出最后剩下的那只猴⼦的编号。

例如,输⼊8 3,输出:7。

[问题分析1]这个例题是由古罗马著名史学家Josephus提出的问题演变⽽来的,所以通常称为Josephus(约瑟夫)问题。

在确定程序设计⽅法之前⾸先来考虑如何组织数据,由于要记录m只猴⼦的状态,可利⽤含m个元素的数组monkey来实现。

利⽤元素下标代表猴⼦的编号,元素的值表⽰猴⼦的状态,⽤monkey[k]=1表⽰第k只猴⼦仍在圈中,monkey[k]=0则表⽰第k只猴⼦已经出圈。

程序采⽤模拟选举过程的⽅法,设变量count表⽰计数器,开始报数前将count置为0,设变量current表⽰当前报数的猴⼦编号,初始时也置为0,设变量out记录出圈猴⼦数,初始时也置为0。

每次报数都把monkey[current]的值加到count上,这样做的好处是直接避开了已出圈的猴⼦(因为它们对应的monkey[current]值为0),当count=n时,就对当前报数的猴⼦作出圈处理,即:monkey[current]:=0,count:=0,out:=out+1。

然后继续往下报数,直到圈中只剩⼀只猴⼦为⽌(即out=m-1)。

参考程序如下:program josephus1a {模拟法,⽤数组下标表⽰猴⼦的编号}const maxm=10000;var m,n,count,current,out,i:integer;monkey:array [1..maxm] of integer;beginwrite('Input m,n:');readln(m,n);for i:=1 to m do monkey[i]:=1;out:=0; count:=0; current:=0;while out<m-1 dobeginwhile count<n dobeginif current<m then current:=current+1 else current:=1;count:=count+monkey[current];end;monkey[current]:=0; out:=out+1; count:=0end;for i:=1 to m doif monkey[i]=1 then writeln('The monkey king is no.',i);readlnend.[运⾏结果]下划线表⽰输⼊Input m,n:8 3The monkey king is no.7 {时间:0秒}Input m,n:10000 1987The monkey king is no.8544 {时间:3秒}[反思] 时间复杂度很⼤O(M*N),对于极限数据会超时。

猴子排序——精选推荐

猴子排序——精选推荐

猴⼦排序基本思想把⼀个⽆序的数组进⾏乱排序,然后看其是否会有序,有可能⼀次之后就有序了,也有可能很多次后依然⽆序。

最佳情况O(n),平均O(n∗n!),最坏可执⾏直到世界的尽头。

猴⼦排序基于⽆限猴⼦定理:⽆限猴⼦定理是数学概率的流⾏⽰例,它说明猴⼦在打字机键盘上随机敲击键,有⾜够的时间和打字机,最终将重现莎⼠⽐亚的全部作品。

根据,算法代码主体就是:while not isInOrder(num):shuffle(num)如果列表已经排序,最好的情况是O(n)。

⽽不是O(1),因为它需要O(n) 才能找到已排序的列表。

最糟糕的情况是O(∞),因为此算法没有上限。

缺陷乱排序,缺陷⼤得很,hh代码实现import java.util.*;public class MonkeySort {public static boolean isOrdered(Integer[] num) {for (int i = 1; i < num.length; i++) {if (num[i-1] > num[i]) {return false;}}return true;}public static void sort(Integer[] num) {List<Integer> list = Arrays.asList(num);while (!isOrdered(num)) { // 判断// System.out.println(list);Collections.shuffle(list); // 随机}}public static void main(String[] args) {Integer[] num = {3,1,2};MonkeySort.sort(num);for (int i = 0; i < num.length; i++) {System.out.print(num[i] + " ");}}}Processing math: 100%。

约瑟夫问题及变种

约瑟夫问题及变种

“约瑟夫”问题及若干变种例1、约瑟夫问题(Josephus)[问题描述]M只猴子要选大王,选举办法如下:所有猴子按1…M编号围坐一圈,从第1号开始按顺序1,2,…,N 报数,凡报到N的猴子退出到圈外,再从下一个猴子开始继续1~ N报数,如此循环,直到圈内只剩下一只猴子时,这只猴子就是大王。

M和N由键盘输入,1≤N,M≤10000,打印出最后剩下的那只猴子的编号。

例如,输入8 3,输出:7。

[问题分析1]这个例题是由古罗马著名史学家Josephus提出的问题演变而来的,所以通常称为Josephus(约瑟夫)问题。

在确定程序设计方法之前首先来考虑如何组织数据,由于要记录m只猴子的状态,可利用含m个元素的数组monkey来实现。

利用元素下标代表猴子的编号,元素的值表示猴子的状态,用monkey[k]=1表示第k只猴子仍在圈中,monkey[k]=0则表示第k只猴子已经出圈。

程序采用模拟选举过程的方法,设变量count表示计数器,开始报数前将count置为0,设变量current 表示当前报数的猴子编号,初始时也置为0,设变量out记录出圈猴子数,初始时也置为0。

每次报数都把monkey[current]的值加到count上,这样做的好处是直接避开了已出圈的猴子(因为它们对应的monkey[current]值为0),当count=n时,就对当前报数的猴子作出圈处理,即:monkey[current]:=0,count:=0,out:=out+1。

然后继续往下报数,直到圈中只剩一只猴子为止(即out=m-1)。

参考程序如下:program josephus1a {模拟法,用数组下标表示猴子的编号}const maxm=10000;var m,n,count,current,out,i:integer;monkey:array [1..maxm] of integer;beginwrite('Input m,n:');readln(m,n);for i:=1 to m do monkey[i]:=1;out:=0; count:=0; current:=0;while out<m-1 dobeginwhile count<n dobeginif current<m then current:=current+1 else current:=1;count:=count+monkey[current];end;monkey[current]:=0; out:=out+1; count:=0end;for i:=1 to m doif monkey[i]=1 then writeln('The monkey king is no.',i);readlnend.[运行结果]下划线表示输入Input m,n:8 3The monkey king is no.7 {时间:0秒}Input m,n:10000 1987The monkey king is no.8544 {时间:3秒}[反思]时间复杂度很大O(M*N),对于极限数据会超时。

数据结构习题及答案 (7)

数据结构习题及答案 (7)

第五章数组和广义表一、选择题1. 常对数组进行的两种基本操作是()(A)建立与删除(B)索引和修改(C)查找和修改(D)查找与索引参考答案:C2.二维数组M的元素是4个字符(每个字符占一个存储单元)组成的串,行下标i的范围从0到4,列下标j的范围从0到5,M按行存储时元素M[3][5]的起始地址与M按列存储时元素( ) 的起始地址相同。

(A)M[2][4](B)M[3][4](C)M[3][5](D)M[4][4]参考答案:B3.数组A[8][10]中,每个元素A的长度为3个字节,从首地址SA开始连续存放在存储器内,存放该数组至少需要的单元数是()。

(A)80(B)100(C)240(D)270参考答案:C4.数组A[8][10]中,每个元素A的长度为3个字节,从首地址SA开始连续存放在存储器内,该数组按行存放时,元素A[7][4]的起始地址为()。

(A)SA+141(B)SA+144(C)SA+222(D)SA+225参考答案:C5.数组A[8][10]中,每个元素A的长度为3个字节,从首地址SA开始连续存放在存储器内,该数组按列存放时,元素A[4][7]的起始地址为()。

(A)SA+141(B)SA+180(C)SA+222(D)SA+225参考答案:B6.稀疏矩阵一般的压缩存储方法有两种,即()。

(A)二维数组和三维数组(B)三元组和散列(C)三元组和十字链表(D)散列和十字链表参考答案:C7.若采用三元组压缩技术存储稀疏矩阵,只要把每个元素的行下标和列下标互换,就完成了对该矩阵的转置运算,这种观点()。

(A)正确(B)错误参考答案:B8.设矩阵A是一个对称矩阵,为了节省存储,将其下三角部分按行序存放在一维数组B[1,n(n-1)/2]中,对下三角部分中任一元素ai,j(i<=j),在一组数组B的下标位置k的值是()。

(A)i(i-1)/2+j-1(B)i(i-1)/2+j(C)i(i+1)/2+j-1 (D)i(i+1)/2+j参考答案:B二、填空题1.己知二维数组A[m][n]采用行序为主方式存储,每个元素占k个存储单元,并且第一个元素的存储地址是LOC(A[0][0]),则A[0][0]的地址是_____________________。

python循环报数游戏python经典面试题之一猴子报数

python循环报数游戏python经典面试题之一猴子报数

python循环报数游戏python经典面试题之一猴子报数Python循环报数游戏——Python经典面试题之一猴子报数猴子报数是一款简单却富有趣味性的游戏。

在这个游戏中,参与者按照事先约定的规则依次报数,数字超过某个指定数值的倍数时,需要说出特定单词。

本文将通过Python代码实现这个游戏,并解析这个题目在面试中的典型应用。

一、游戏规则在猴子报数游戏中,参与者按照从1开始的自然数依次报数,规则如下:1. 遇到3的倍数,需要说出"Fizz";2. 遇到5的倍数,需要说出"Buzz";3. 遇到同时是3和5的倍数,需要说出"FizzBuzz";4. 其他情况下,直接说出当前数字。

例如,当参与者报数到15时,报数结果应为:1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz。

二、Python代码实现以下是使用Python编写的猴子报数游戏的代码:```pythondef monkey_count(n):result = []for i in range(1, n+1):if i % 3 == 0 and i % 5 == 0:result.append("FizzBuzz")elif i % 3 == 0:result.append("Fizz")elif i % 5 == 0:result.append("Buzz")else:result.append(str(i))return resultn = 15output = monkey_count(n)print(output)```上述代码中,我们定义了一个名为`monkey_count`的函数,该函数接受一个参数`n`,表示参与者报数的最大值。

用C编写程序猴子选大王

用C编写程序猴子选大王

湖南人文科技学院计算机系课程设计说明书课程名称: 数据结构课程代码:题目: 猴子选大王年级/专业/班: 06级计算机科学与技术专业一班学生姓名:学号:06408109 06408102 06408107 0640812206408103指导教师: 刘刚常开题时间: 2008 年 6 月16 日完成时间: 2008 年 6 月29 日目录摘要 (3)一、引言 (4)二、设计目的与任务 (4)三、设计方案 (5)1、总体设计 (5)2、详细设计 (8)3、程序清单 (14)4、程序调试与体会 (22)5、运行结果 (23)四、结论 (24)五、致谢 (24)六、参考文献 (25)摘要本文首先介绍顺序表和链表并作以比较,我们分别使用循环队列和循环链表来解决猴子选大王的问题,程序使用了C语言编写,有很少一部分函数是用C++编写的,有比较详细的中文注释并在VC++下调试运行通过。

整个程序使用中文界面,并有相应的提示信息,便于操作和程序运行。

关键词:循环队列;循环链表;存储结构AbstractThis paper details the difference of sequence list and linklist.We respectively use queue and circular queue and circular linked list to solve the seek elected king of the monkey problem . The procedure write with C language ,a very small part function is used by the C + +,and has chinese explanatory note.What’s more,it was debugged in VC++ debugger and run very well.The whole procedure,with Chinese interface and thecorresponding hints,is convenient to run and easy to be operated.Keywords : circular queue;circular linked list ;storage structure《数据结构》课程设计——猴子选大王一、引言数据结构是一门非常重要的基础学科,但是实验内容大都不能很好的和实际应用结合起来。

猴子选大王问题

猴子选大王问题

猴子选大王问题集团文件版本号:(M928-T898-M248-WU2669-I2896-DQ586-M1988)这是17世纪的法国数学家加斯帕在《数目的游戏问题》中讲的一个故事:15个教徒和15个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。

问怎样排法,才能使每次投入大海的都是非教徒。

*问题分析与算法设计约瑟夫问题并不难,但求解的方法很多;题目的变化形式也很多。

这里给出一种实现方法。

题目中30个人围成一圈,因而启发我们用一个循环的链来表示。

可以使用结构数组来构成一个循环链。

结构中有两个成员,其一为指向下一个人的指针,以构成环形的链;其二为该人是否被扔下海的标记,为1表示还在船上。

从第一个人开始对还未扔下海的人进行计数,每数到9时,将结构中的标记改为0,表示该人已被扔下海了。

这样循环计数直到有15个人被扔下海为止。

[编辑本段]约瑟夫问题的一般形式:约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。

例如N=6,M=5,被杀掉的人的序号为5,4,6,2,3。

最后剩下1号。

假定在圈子里前K个为好人,后K个为坏人,你的任务是确定这样的最少M,使得所有的坏人在第一个好人之前被杀掉。

C++代码示例:#include<iostream>usingnamespacestd;voidmain(){intn,m,a[101],k,i,j,num;//计数器是从1开始的,所以100个人用101cout<<"请输入参加游戏的玩家人数(不超过100人):";cin>>n;cout<<"----------------------------------------"<<endl;if(n>100){cout<<"玩家太多,请重新登陆此程序!"<<endl;return;}cout<<"输入游戏中要玩的数字:";cin>>m;cout<<"----------------------------------------"<<endl;for(i=1;i<=n;i++){a【i】=1;//注意百度百科里不让使用ASCII里的方括号,这里是中文字符集里的方括号,}j=0;k=0;for(i=1;i<=n+1;i++){if(a【i】==1){j=j+a【i】;if(j==m){j=0;a【i】=0;k++;}if(k==n){num=i;break;}}if(i==n+1)i=0;}cout<<"最后获胜的玩家是第"<<num<<"号玩家!"<<endl;cout<<"----------------------------------------"<<endl; }写完密码约瑟夫就想到原来看到约瑟夫问题的一个数学解法很巧妙很简单不过只能推出最后一个出列的人无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。

猴子选大王问题

猴子选大王问题

这是17世纪的法国数学家加斯帕在《数目的游戏问题》中讲的一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。

问怎样排法,才能使每次投入大海的都是非教徒。

*问题分析与算法设计约瑟夫问题并不难,但求解的方法很多;题目的变化形式也很多。

这里给出一种实现方法。

题目中30个人围成一圈,因而启发我们用一个循环的链来表示。

可以使用结构数组来构成一个循环链。

结构中有两个成员,其一为指向下一个人的指针,以构成环形的链;其二为该人是否被扔下海的标记,为1表示还在船上。

从第一个人开始对还未扔下海的人进行计数,每数到9时,将结构中的标记改为0,表示该人已被扔下海了。

这样循环计数直到有15个人被扔下海为止。

[编辑本段] 约瑟夫问题的一般形式:约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。

例如N=6,M=5,被杀掉的人的序号为5,4,6,2,3。

最后剩下1号。

假定在圈子里前K个为好人,后K个为坏人,你的任务是确定这样的最少M,使得所有的坏人在第一个好人之前被杀掉。

C++代码示例: #i n c l u d e<i o s t r e a m>u s i n g n a m e s p a c e s t d;v o i d m a i n()i n t n,m,a[101],k,i,j,n um; //计数器是从1开始的,所以100个人用101 c o u t<<"请输入参加游戏的玩家人数(不超过100人):";c i n>>n;c o u t<<"----------------------------------------"<<e nd l;i f(n>100){c o u t<<"玩家太多,请重新登陆此程序!"<<e nd l;r e t u r n;}c o u t<<"输入游戏中要玩的数字:";c i n>>m;c o u t<<"----------------------------------------"<<e nd l;f o r(i=1;i<=n;i++){ a【i】=1;//注意百度百科里不让使用ASCII里的方括号,这里是中文字符集里的方括号,}j=0;k=0;f o r(i=1;i<=n+1;i++){i f(a【i】==1){j=j+a【i】;i f(j==m)j=0;a【i】=0;k++;}i f(k==n){n u m=i;b r e a k;}}i f(i==n+1)i=0;}c o u t<<"最后获胜的玩家是第"<<n u m<<"号玩家!"<<e nd l;c o u t<<"----------------------------------------"<<e nd l;}写完密码约瑟夫就想到原来看到约瑟夫问题的一个数学解法很巧妙很简单不过只能推出最后一个出列的人无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。

猴子选大王(数据结构)

猴子选大王(数据结构)

猴子选大王(数据结构)编程思想:首先人为地输入要参与的人数m,和要求第一次出列的人的序号n。

然后根据输入的m值构造一个单向环链,每一个节点包括序号域(每个人各自的序号),密码域(记录当他出环后下一个出环的人是从他数后面的第几个人,由随机函数random()+1生成,加一的目的是防止生成数为零),链域(链接下各结点)。

然后再主程序总主要通过一个while循环实现功能,流程图如下:#include<stdio.h>#include<malloc.h>struct Node{int data;struct Node *next;};//建立一个节点结构体int main(void){struct Node *head, *s, *q, *t;int n, m, count=0, i;printf("n <= m\n");do{printf("input the monkey number m:");scanf("%d",&m);printf("input the number n:");scanf("%d",&n);}while(n >= m);for(i=0; i<m; i++){s=(struct Node *)malloc(sizeof(struct Node));s->data=i+1;s->next=NULL;if(i==0){head=s;q=head;}else{q->next=s;q=q->next;}}//建立一个不带头结点的单链表q->next=head;//这里,将单链表组成环状,形成循环单链表printf("before:\n");q=head;while(q->next!=head){printf("%d ",q->data);q=q->next;}if(q->next==head)printf("%d",q->data);printf("\noutput:\n");//依次输出节点的值printf("%d ",q->data);q=head;do{count++;//计数器开始计数if(count==n-1){t=q->next;q->next=t->next;//到n前面那个节点stop,然后删除第n个节点count=0;//计数器复位printf("%d ", t->data);//输出被淘汰的猴子的号码free(t);//释放内存,防止内存泄露}q=q->next;}while(q->next!=q);//循环到只剩下一个节点printf("\nthe king is: %d \n",q->data);//输出king的号码return 0;}。

讲题比赛讲稿

讲题比赛讲稿

讲题比赛讲稿一、问题的提出我今天要讲的是第12题。

题目为:有2015个同学站成一个圆圈,按顺时针方向编号:1—2015。

现在从1号开始,按“0、1、0、1、0、1……”的方式报数,报到1的同学立即离开,不再参与报数。

到最后只剩一个同学时报数停止。

请问最后留下的这个同学的编号是多少?二、问题分析这道题其实源于一道很有意思约瑟夫问题。

约瑟夫问题,有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。

据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数3该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。

然而Josephus 和他的朋友并不想遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

回到我今天要讲的题目。

题目中将约瑟夫问题中的报数方式置换成“0、1、0、1……”循环报数,而且将结果也变成了“最后留下的同学的编号是多少?”虽然题目条件有了变化,但是仍然属于“约瑟夫问题”,可以用该类方法进行分析和解决。

三、问题的研究拿到题目以后,我们对此题的研究经历了三个阶段。

第一阶段:自我摸索阶段拿到题后,我简直有点懵。

说实话,我从来没有遇到过这样的题。

不过我想,通过网络搜索应该会有些眉目。

可是当我将原题输入百度以后,却找不到答案。

我只能对着题目,自己动手研究了。

首先我想到数的奇偶问题。

当总人数为奇数时,第一轮留下的是所有奇数编号;而到第二轮……情况比较复杂了。

而当总人数为偶数时,那么第一轮排除的是偶数编号;第二轮排除的就是4n的编号;第三轮时,剩下的编号可能是奇数个,怎么办呢?再次受挫的我只能像个小学生一样从最原始的方法开始模拟游戏过程。

我从3人开始研究3人留下的是3号;4人留下的是1号……当研究到8人留下是1号时,我恍如黑暗中窥见无限光明。

PHP实现的猴王算法(猴子选大王)示例

PHP实现的猴王算法(猴子选大王)示例

PHP实现的猴王算法(猴⼦选⼤王)⽰例本⽂实例讲述了PHP实现的猴王算法。

分享给⼤家供⼤家参考,具体如下:<?phpfunction getKingMokey($n, $m){$monkey[0] = 0;//将1-n只猴⼦顺序编号⼊数组中for($i= 1; $i<= $n; $i++){$monkey[$i] = $i;}$len = count($monkey);//循环遍历数组元素(猴⼦编号)for($i= 0; $i< $len; $i= $i){$num = 0;foreach($monkey as $key => $value){if($value == 0) continue;$num++;$values = $value;}//若只剩⼀只猴⼦则输出该猴⼦编号(数组元素值) 并退出循环if($num == 1){echo $values;exit;}//将第$i只猴⼦踢出队伍(相应数组位置元素值设为0)$monkey[$i] = 0;//打印该猴⼦位置echo $i."";//设置计数器for($j= 1; $j<= $m; $j++){//猴⼦编号加⼀,遍历下⼀只猴⼦$i++;//若该猴⼦未被踢出队伍,获取下⼀只猴⼦编号if($monkey[$i] > 0) continue;//若元素值为0,则猴⼦已被踢出队伍,进⽽循环取下⼀只猴⼦编号if($monkey[$i] == 0){//取下⼀只猴⼦编号for($k= $i; $k< $len; $k++){//值为0,编号加1if($monkey[$k] == 0) $i++;//否则,编号已取得,退出if($monkey[$k] > 0) break;}}//若编号⼤于猴⼦个数,则从第0只猴⼦开始遍历(数组指针归零)//步骤同上if($i == $len) $i = 0;//同上步骤,获取下⼀只猴⼦编号if($monkey[$i] == 0){for($k= $i; $k< $len; $k++){if($monkey[$k] == 0) $i++;if($monkey[$k] > 0) break;}}}}}//猴⼦个数$n = 10;//踢出队伍的编号间隔值$m = 3;//调⽤猴王获取函数getKingMokey($n, $m);>运⾏结果:036927185104⽤递归的算法$monkeys = array(1 , 2 , 3 , 4 , 5 , 6 , 7, 8 , 9 , 10); //monkey的编号$m = 4; //数到第⼏只的那只猴⼦被踢出去function killMonkey($monkeys , $m , $current = 0){$number = count($monkeys);$num = 1;if(count($monkeys) == 1){echo $monkeys[0]."成为猴王了";return;}else{while($num++ < $m){$current++ ;$current = $current%$number;}echo $monkeys[$current]."的猴⼦被踢掉了<br/>";array_splice($monkeys , $current , 1);killMonkey($monkeys , $m , $current);}}killMonkey($monkeys , $m);运⾏结果:4的猴⼦被踢掉了8的猴⼦被踢掉了2的猴⼦被踢掉了7的猴⼦被踢掉了3的猴⼦被踢掉了10的猴⼦被踢掉了9的猴⼦被踢掉了1的猴⼦被踢掉了6的猴⼦被踢掉了5成为猴王了更多关于PHP相关内容感兴趣的读者可查看本站专题:《》、《》、《》、《》、《》及《》希望本⽂所述对⼤家PHP程序设计有所帮助。

C++猴子选大王 choose monkey king

C++猴子选大王 choose monkey king
return0;
}
猴子状态初始化为1表示可能被选上为0表明没希望了
#include <iostream>
usingnamespacestd;
classmonkey
{
private:intnum,del;
public:
monkey(intn,intd):num(n),del(d){}//构造函数
intchoose(intnum,intdel)
}
delete[]a;
}
};
intmain()
{
intnum,del;
cout<<"请输入猴子总数M和淘汰号N:";
cin>>num>>del;
monkeymonkeygroup(num,del);
cout<<"第"<<monkeygroup.choose(num,del)+1<<"个猴子为大王!"<<endl;
{
countOne=0;
for(i=0;i<num;i++)
{
sum+=a[i];
if(sum==del)
sum=a[i]=0; //淘汰倒霉猴子;
countOne+=a[i];
}
}
for(i=0;i<num;i++)
if(a[i]!=0){
delete[]a;
return i; //找到幸运猴子编号(从0开始的);
{
inti;
int*a;
a = newint[num];
for(i[i]=1; //猴子状态初始化,为1表示可能被选上,为0表明没希望了;

猴子选大王c++ 程序

猴子选大王c++ 程序
while(count>1)//猴子的数目大于1表明还有其他的猴子被选中
{
count=0;
for(i=0;i<number;i++)
{ sum=sum+a[i];
if(sum==del)
sum=a[i]=0;//猴子被淘汰
count=count+a[i];//到count的值为1时结束循环,表明只剩一只猴子为大王
monkey monkey(p,q);//定义一个monk总数M和淘汰猴子N:";
cin>>p>>q;
cout<<monkey.choose(p,q)+1<<endl;
return 0;}
#include<iostream>
using namespace std;
class monkey//定义一个类
{
private:
int number;
int del;
public:
monkey(int n,int d){number=n,del=d;}//建立一个构造函数
int choose(int number,int del)
{int i;
int *a;
a=new int[number];//用new来开辟内存
for(i=0;i<number;i++)
a[i]=1;//是1的被选中,0的话不被选中
int sum=0;//初始化
int count=number;
if(del==1)
{return (number-1);}

链表_猴子选大王

链表_猴子选大王
猴子选大王
• 题目描述:n只猴子要选大王,选举方法如下: 所有猴子按 1,2 ……… n 编号并按照顺序围成 一圈,从第 k 个猴子起,由1开始报数,报到m 时,该猴子就跳出圈外(从链表中删除),下 一只猴子再次由1开始报数,如此循环,直到圈 内剩下一只猴子时,这只猴子就是大王。 • 输入数据:猴子总数n,起始报数的猴子编号k, 出局数字m • 输出数据:猴子的出队序列和猴子大王的编号
要求:
• 要求在两节课内完成编程和设计 • 在下课前提交给老师检查,并登记成绩,下课铃 声响起后停止检查 • 要求用链表实现,链表的创建、输出、删除等功 能分别由函数实现 • 检查时录入数据值是: n=5,k=2,m=3 • 正确输出应该是
– 跳出圈外的猴子依次为:4 2 1 3 – 5是大王
ห้องสมุดไป่ตู้
正确输出分析n=5,k=2,m=3 • • • • • 12345 1235 135 35 5 4跳出 2跳出 1跳出 3跳出 5是大王

猴子选大王问题

猴子选大王问题

这是17世纪的法国数学家加斯帕在《数目的游戏问题》中讲的一个故事:15个教徒和15个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。

问怎样排法,才能使每次投入大海的都是非教徒。

*问题分析与算法设计约瑟夫问题并不难,但求解的方法很多;题目的变化形式也很多。

这里给出一种实现方法。

题目中30个人围成一圈,因而启发我们用一个循环的链来表示。

可以使用结构数组来构成一个循环链。

结构中有两个成员,其一为指向下一个人的指针,以构成环形的链;其二为该人是否被扔下海的标记,为1表示还在船上。

从第一个人开始对还未扔下海的人进行计数,每数到9时,将结构中的标记改为0,表示该人已被扔下海了。

这样循环计数直到有15个人被扔下海为止。

[编辑本段]约瑟夫问题的一般形式:约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。

例如N=6,M=5,被杀掉的人的序号为5,4,6,2,3。

最后剩下1号。

假定在圈子里前K个为好人,后K个为坏人,你的任务是确定这样的最少M,使得所有的坏人在第一个好人之前被杀掉。

C++代码示例:#include<iostream>usingnamespacestd;voidmain(){intn,m,a[101],k,i,j,num;//计数器是从1开始的,所以100个人用101cout<<"请输入参加游戏的玩家人数(不超过100人):";cin>>n;cout<<"----------------------------------------"<<endl;if(n>100){cout<<"玩家太多,请重新登陆此程序!"<<endl;return;}cout<<"输入游戏中要玩的数字:";cin>>m;cout<<"----------------------------------------"<<endl;for(i=1;i<=n;i++){a【i】=1;//注意百度百科里不让使用ASCII里的方括号,这里是中文字符集里的方括号,}j=0;k=0;for(i=1;i<=n+1;i++){if(a【i】==1){j=j+a【i】;if(j==m){j=0;a【i】=0;k++;}if(k==n){num=i;break;}}if(i==n+1)i=0;}cout<<"最后获胜的玩家是第"<<num<<"号玩家!"<<endl; cout<<"----------------------------------------"<<endl;}写完密码约瑟夫就想到原来看到约瑟夫问题的一个数学解法很巧妙很简单不过只能推出最后一个出列的人无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

// 让q指向链表尾部结点
// 链表尾部指向空 // 循环体结束 // 链表尾 // 链表尾部指向链表头,
// 形成循环链表
// 函数体结束
12
// 被调用函数select,mm表示结点删除间隔 void select(int mm) { // 函数体开始 int x=0; // 声明整型值x,并初始化为0 struct mon *p,*q; // 声明结构指针p,q q=tail; // q赋值为tail,指向循环链表尾部 do // 直到型循环,用于循环删除指定间隔的结点 { // 循环体开始 p=q->next; // p赋值为q相邻的下一个结点 x=x+1; // x加1 if(x % mm==0) // x是否整除mm, { // 表示是否跳过指定间隔
// 输出被删掉的猴子号
}
} else q=p; }while(q!=q->next); head = q;
printf("被删掉的猴子号为%d号\n",p->num); q->next=p->next; // 删除此结点 free(p); // 释放空间
// q指向相邻的下一个结点p // 剩余结点数不为1,则继续循环 // head指向结点q,q为链表中剩余一个结点 13 // 函数体结束
3 4 8
q
8
这个do-while循环的退出条件是q==q->next。即当只 剩下一个结点时才退出循环。当然猴王非其莫属了。 这时,让头指针head指向q,head是全局变量,在 主程序最后输出猴王时要用head->num。 q
head
7
参考程序如下:
9
#include <stdio.h> #include <malloc.h> #define null 0
(3)最后一个结点要和头结点用下一语句链接到一起 tail = q; tail->next = head;
q
head
tail
6
5、删结点的函数select(int mm) mm为形式参数,从1至m报数,凡报到mm者删除其 所在的结点。 设计两个指针p和q。一开始让q指向链表的尾部q=tail。 让p指向q的下一个结点。开始时让p指向1#猴所在的结点。 用一个累加器x,初始时x=0,从1#猴所在结点开始让 x=x+1=1,如果mm是1的话,1#猴所在的p结点就要被删 除。有三条语句 printf(“被删掉的猴子号为%d号\n”,p->num); q->next = p->next; 演示 free(p);
head
p
1 2
q tail
8
7
这里free(p)是释放p结点所占用的内存空间的语句。 如果mm不是1而是3,程序会在do-while循环中, 让x加两次1,q和p一起移动两次,p指向3#所在结 点,q指向2#所在结点,之后仍然用上述三条语句 删去3#所在的结点。
演示
p q head
1 2
q p
p
11
for(i=2;i<=nn;i=i+1) // 利用循环结构构造链表
{ // 循环体开始 p=(struct mon *)malloc(LEN);// 为p分配内存空间 p->num=i; // 初始化p结点num域为i,表示猴子号 q->next=p; // 将p结点加到链表尾部
q=p;
p->next=null; } tail = q; tail->next=head; }
4
1、定义一个名为mon的结构 struct mon { int num; // 整数,表示猴子的编号 struct mon *next; // 指针,指向相邻的下一 只猴子 }
2、将链表的头指针head定义为全局变量。 struct mon*head; 3、主函数 用键盘输入猴子数n,输入数m,调用函数create建立一个 循环链表,模拟众猴围成一圈的情况。该函数的实参为n。 调用函数select,模拟1至m报数,让n-1只猴子逐一出列 的过程。即在具有n个结点的循环链表按报数m删除结点的 5 过程。该函数的实参为m,最后输出猴王的编号。
4、建立循环链表的函数create(int nn) 其中nn为形式参数。要从编号1到编号nn。思路是
(1)先做第1个结点,让其中的数据域p->num赋值为1,让 指针域赋值为null。之后让链头指针head指向第1个结点。 利用指针q记住这个结点,以便让指针p去生成下面的结 点。
(2)利用一个计数循环结构,做出第2个结点到第nn个结点。 并将相邻结点一个接一个链接到一起。
struct mon *head, *tail; // mon结构指针,全局变量
10
void create(int nn) { int i; struct mon *p,*q;
// 被调用函数 // 函数体开始 // 整型变量i,用于计数 // 声明mon结构指针p,q
// 为p分配内存空间 p=(struct mon *) malloc(LEN); p->num=1; p->next=null; head=p; q=p; // 初始化p结点num域为1 // 初始化p结点next域为空 // 链表头指针head赋值为p // q赋值为p
14
循环链表
1
循环链表
例:猴子选大王。 n只猴子围成一圈,顺时针方向从1到n编号。 之后从1号开始沿顺时针方向让猴子从1, 2,…,m依次报数,凡报到m的猴子,都让 其出圈,取消候选资格。然后不停地按顺时 针方向逐一让报出m者出圈,最后剩下一个 就是猴王。
2
演示:n=8, m=3
8
1
起始位置 2
7
3
void main() { int n,m; head = null;
Байду номын сангаас
// 主函数开始 // 函数体开始 // 声明整型变量n,m // 初始化head为空
printf("请输入猴子数\n"); // 提示信息 scanf("%d",&n); // 输入待插入结点数据 printf("请输入间隔m\n"); // 提示信息 scanf("%d",&m); // 输入间隔 create(n); // 调用函数create建立循环链表 select(m); // 调用函数select,找出剩下的猴子 printf("猴王是%d号\n",head->num); // 输出猴王 } // 函数体结束
// 预编译命令 // 内存空间分配 // 定义空指针常量
// 定义常量,表示结构长度 #define LEN sizeof(struct mon) struct mon { int num; struct mon *next; }; // 结构声明 // 整型数,用于记录猴子号 // mon结构指针
猴王
6 5
4
猴子被淘汰的顺序
3
6
1
5
2
8
4
3
说明:
如图1所示有8只猴子围成一圈,m=3。从1# 猴的位置开始,顺时针1至3报数,第一个出 圈的是3#;第二个出圈的是6#,第3个出圈 的是1#;第4个出圈的是5#;第5个是2#,第 6个是8#;第7个是4#。最后剩下一个是7#, 它就是猴王。
我们用循环链表来模拟这个选择过程。
相关文档
最新文档