C++约瑟夫问题
约瑟夫问题面向对象(C++版)程序设计报告
函数
相关说明
Jose(int boys, int interval, int begin=1);
构造函数,主要功能初始化各个参数,校验输出的m、n、s参数为int boys, int interval, int begin=1
void getWinner()const;
//构造函数
//-------------------------------------
BoyRing::BoyRing(int n)
{
if(n<2) throw exception(); //发生错误时自动跳出
pBegin = new Boy[n]; //申请一个新的Boy空间,pBegin指向该空间的开始处
for(int i=1; i<=n; i++)
{
pBegin[i-1].next = &pBegin[i%n];//形成链表
pBegin[i-1].code = i;//给孩子孩子编号
}
pivot = pCurrent = &pBegin[n-1];//各指针初始化
}
//------------------------------------
2详细设计
2.1程序结构
改程序分成三个抽象层次,第一层是应用层,直接指使Jose类对象去完成求解工作;第二层是Jose类层,描述Josephus问题的求解细节;第三层是BoyRing类层,辅助Jose类完成求解过程(上述三层间的关系描述如图J-1,这也是程序模块间的关系)。
图J-1.对象实现中程序模块的相互关系
void disengage();
利用指针实现小孩离队,无参数
C语言编程题目000
题1. 统计字母的使用频率一、题目:统计字母的使用频率二、目的与要求1.目的:通过编写程序统计字母的使用频率,培养学生综合利用C语言进行程序设计的能力,熟悉字符串的操作方法,加强函数的运用,提高软件系统分析能力和程序文档建立、归纳总结的能力。
2.基本要求:1)要求用C语言编程,在Visual C++环境下调试完成;2)要求按照程序功能分成几个功能模块来实现,各个功能模块分别使用函数来完成;3)要求应用本课所讲授的程序设计语言知识来解决问题三、设计方法和基本原理1.课题功能描述本程序的功能,就是要统计英文字母的使用频率。
2.问题详细描述为统计英文字母的使用频率,输入一个不包括空格的由英文字母组成的字符串,长度不超过200个字符。
统计26个英文字母的使用频率,不区分大小写。
最后按使用频率从大到小输出字母(小写字母)和使用频率(出现的次数)。
3.问题的解决方案按照程序要求,本程序应采用模块化设计方法,设计几个功能模块。
例如(仅供参考):l 将字符串中的大写字母转换为小写字母l 统计输入的字符串中字母的使用频率l 按使用频率从大到小进行排序主函数中控制输入、函数调用和输出。
四、主要技术问题的描述根据三的分析,主要问题在于:1) 为统计字母的使用频率,定义一个长度为26的int数组存放所统计的各个字母的使用频率。
2) 在统计字母的使用频率时,不要使用if语句或switch语句,利用字母的ASCII码与数组元素下标之间的关系来求得。
3) 按使用频率从大到小进行排序时,建议使用指针数组更为方便。
五、创新要求实现程序功能后,可进行创新设计:1) 使用多文件,即主函数和各个函数分别存放在不同的.c文件中,在头文件中进行函数原型声明。
2) 读入一篇英文文档,并对其进行字母频率分析。
题2.指示灯控制问题描述:N盏灯排成一排,从1到N按顺序依次编号。
有N个人也从1到N依次编号。
第一个人(1号)将灯全部关闭。
第二个人(2号)将凡是2和2的倍数的灯打开。
约瑟夫环问题
约瑟夫环问题问题描述:有n个⼈,编号分别从0到n-1排列,这n个⼈围成⼀圈,现在从编号为0的⼈开始报数,当报到数字m的⼈,离开圈⼦,然后接着下⼀个⼈从0开始报数,依次类推,问最后只剩下⼀个⼈时,编号是多少?分析:这就是著名的约瑟夫环问题,关于来历不再说明,这⾥直接分析解法。
解法⼀:蛮⼒法。
我曾将在⼤⼀学c语⾔的时候,⽤蛮⼒法实现过,就是采⽤标记变量的⽅法即可。
解法⼀:循环链表法。
从问题的本质⼊⼿,既然是围成⼀个圈,并且要删除节点,显然符合循环链表的数据结构,因此可以采⽤循环链表实现。
解法三:递推法。
这是⼀种创新的解法,采⽤数学建模的⽅法去做。
具体如下:⾸先定义⼀个关于n和m的⽅程f(n,m),表⽰每次在n个编号0,1,...,n-1中每次删除的报数为m后剩下的数字,在这n个数字中,第⼀个被删除的数字是(m-1)%n,为了简单,把(m-1)%n记作k,那么删除k之后剩下的数字为0,1,2,...,k-1,k+1,...,n-1并且下⼀次删除的数字从k+1开始计数,这就相当于剩下的序列中k+1排在最前⾯,进⽽形成k+1,..,n-1,0,1,2,...,k-1这样的序列,这个序列最后剩下的数字应该和原序列相同,由于我们改变了次序,不能简单的记作f(n-1,m),我们可以记作g(n-1,m),那么就会有f(n,m)=g(n-1,m).下⼀步,我们把这n-2个数字的序列k+1,..,n-1,0,1,2,...,k-1做⼀个映射,映射的结果是形成⼀个从0到n-2的序列。
k+1对0,k+2对1,......,n-1对n-k-2,0对n-k-1,1对n-k,....,k-1对n-2这样我们可以把这个映射定义为p,则p(x)=(x-k-1)%n,它表⽰如果映射前的数字是x,映射后为(x-k-1)%n,从⽽这个映射的反映射问为p-1(x)=(x+k+1)%n由于映射之后的序列和原始序列具有相同的形式,都是从0开始的序列,所以可以⽤函数f来表⽰,即为f(n-1,m),根据映射规则有:g(n-1,m)=p-1[f(n-n,m)]=[f(n-1,m)+k+1]%n,最后把之前的k=(m-1)%n带⼊式⼦就会有f(n,m)=g(n-1,m)=[f(n-1,m)+m]%n.这样我们就可以得出⼀个递推公式,当n=1时,f(n,m)=0;当n>1时,f(n,m)=[f(n-1,m)+m]%n;有了这个公式,问题就变得多了。
约瑟夫环问题源代码(C语言)
约瑟夫环问题如下:已知n个人(n>=1)围桌一园桌周围,从1开始顺序编号。
从序号为1的人开始报数,顺时针数到m的那个人出列。
他的下一个人又从1开始报数,数到m的那个人又出列。
依此规则重复下去,直到所有人全部出列。
求解最后一个出列的人的编号。
本次实验是以顺序表求解约瑟夫环问题,程序流程图及程序运行结果如下:输入人数、所报数、第一个报数人编号存储并建立一个约瑟夫环通过循环结构依次查找每次出列的人的编号并输出输出最后一个出列的人的编号程序代码如下:#include<iostream>#include<process.h>#include<stdlib.h>using namespace std;struct Node //循环节点的定义{int number; //编号Node *next;};Node *CreateList(Node *L,int &n,int &m); //建立约瑟夫环函数void Joseph(Node *L,int n,int m); //输出每次出列号数函数Node *DeleteList(Node **L,int i,Node *q); //寻找每次出列人的号数int LengthList(Node *L); //计算环上所有人数函数void main() //主函数{system("color 75"); //设置颜色以美观Node *L;L=NULL; //初始化尾指针int n, m;cout<<"请输入人数N:";cin>>n; //环的长度if(n<1){cout<<"请输入正整数!";} //人数异常处理else{cout<<"请输入所报数M:";cin>>m;if(m<1){cout<<"请输入正整数!";} //号数异常处理else{L=CreateList(L,n,m); //重新给尾指针赋值Joseph(L,n,m);}}system("pause");}Node *CreateList(Node *L,int &n,int &m) //建立一个约瑟夫环(尾插法){Node *q;for(int i=1;i<=n;i++){Node *p;p=new Node;p->number=i;p->next=NULL;if(i==1) L=q=p; //工作指针的初始化 else{q->next=p;q=q->next;}}q->next=L;if(L!=NULL){return(L);} //返回尾指针else cout<<"尾指针异常!"<<endl; //尾指针异常处理}void Joseph(Node *L,int n,int m) //输出每次出列的人{int k;cout<<"请输入第一个报数人:";cin>>k;if(k<1||k>n){cout<<"请输入1-"<<n<<"之间的数"<<endl;}else{cout<<"\n出列顺序:\n";for(int i=1;i<n;i++){Node *q = new Node;if(i==1) q=DeleteList(&L,k+m-1,q); //第一个出列人的号数else q=DeleteList(&L,m,q);cout<<"号数:"<<q->number<<endl;delete q; //释放出列人的存储空间}cout<<"最后一个出列号数是:"<<L->number<<endl; //输出最后出列人的号数}}Node *DeleteList(Node **L,int i,Node *q) //寻找每次出列的人{if(i==1) i+=LengthList(*L); //顺序依次出列情况的处理方式Node *p;p=*L;int j=0;while(j<i-2) {p=p->next;j++;}q = p->next;p->next=p->next->next;*L = p->next;return(q);}int LengthList(Node *L) //计算环上的人数{if(L){cout<<"尾指针错误!"<<endl;} //异常处理else{int i=1;Node *p=L->next;while(p!=L){i++;p=p->next;}return(i);}}实验体会:通过对本问题的分析,我进一步熟悉了对各种逻辑表达式的判断和指针的使用。
约瑟夫问题pascal
约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。
在计算机编程的算法中,类似问题又称为约瑟夫环。
又称“丢手绢问题”)据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
然而Josephus 和他的朋友并不想遵从。
首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。
接着,再越过k-1个人,并杀掉第k个人。
这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。
问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
//详情请见百度百科。
[题目描述]Josephus问题是建立在历史学家Josephus的一个报告的基础之上,该报告讲述了他和40个士兵在公元67年被罗马军队包围期间签定的一个自杀协定,Josephus建议每个人杀死他的邻居,他很聪明的使自己成为这些人中的最后一个,因此获得生还。
21世纪的今天,我们将Josephus问题稍作扩展:设N个人围成一圈,依次从1到N编号,从第S号开始报数,报到K的人出列,求第T个出列的人的编号。
显然,Josephus面对的是N = 40, K = 2, S= 1, T = 40的退化情况。
[数据范围]30%的数据,K = 2100%的数据,1 <= N <= 1000000, 1<= K <= 2147483647, 1 <= S <= N, 1 <= T <= N最简单的推导方法应该是模拟。
约瑟夫问题的C++代码
#include<iostream>using namespace std;struct Node//定义节点的结构类型{int data;Node* next;};class CircularLinkedList//循环链表类{public:CircularLinkedList(){first=new Node;first->next=NULL;}CircularLinkedList(int n);//构建一个附有值的循环链表~CircularLinkedList();int Josephus(int num);//约瑟夫函数private:Node* first;};CircularLinkedList::CircularLinkedList(int n){first=new Node;Node * r=first;for(int i=1;i<=n;i++){Node* s=new Node;s->data=i;s->next=NULL;r->next=s;r=s;} //头插法初始化链表r->next=first; //最后一个元素的next志指向头结点}CircularLinkedList::~CircularLinkedList(){Node* p=first,*q;while(p->next!=first)//p指向最后一个结点时结束循环{q=p;p=p->next;delete q;}delete p;//删除头结点}int CircularLinkedList::Josephus(int num){Node* p=first,*q;if(num<=0)throw "输入错误!";while(first->next->next!=first){for(int i=1;i<num;i++) //p向后移动num位,指向要删除的元素的前一个结点{p=p->next;if(p==first) //若循环过程中出现p指向头结点,则跳过头结点{p=p->next;}}if(p->next==first) //若循环结束后p指向最后一个元素,则要跳过头结点,并让头结点的next指向要删除元素的下一个{p=first;q=p->next;p->next=q->next;//first->next=q->next;cout<<q->data<<" ";delete q;}else{q=p->next;p->next=q->next;cout<<q->data<<" ";delete q;}}cout<<endl;cout<<"最后一个数为:";return first->next->data;}void main(){int n,m;cout<<"请输入约瑟夫问题的人数和间隔人数:";cin>>n>>m;cout<<"依次删除:"<<endl;CircularLinkedList Josephus1(n);//创建的对象调用第二个构造函数cout<<Josephus1.Josephus(m)<<endl;}。
C++约瑟夫环的实例代码
C++约瑟夫环的实例代码C++ 约瑟夫环的实例代码约瑟夫环是⼀个数学的应⽤问题:已知n个⼈(以编号1,2,3...n分别表⽰)围坐在⼀张圆桌周围。
从编号为k的⼈开始报数,数到m的那个⼈出列;他的下⼀个⼈⼜从1开始报数,数到m的那个⼈⼜出列;依此规律重复下去,直到圆桌周围的⼈全部出列。
分析:有n个⼈,要想所有的⼈都退出去,只有每个⼈喊到m,才可以退完,所以可以算出,n*m为所有⼈总共报数的总次数。
代码:/** 约瑟夫出圈*/#include <stdio.h>int main(){char peo[100] ;char *p_peo = peo;int i , n , skip , flag[100] = {0} , cnt;int *p_flag = NULL;printf("请输⼊⼈数:");scanf("%d", &n);printf("所有⼈如下:\n");for(p_peo , i = 0 ; p_peo < peo + n ; ++p_peo , ++i){*p_peo = 'a' + i;printf("%c ", *p_peo);}printf("\n");printf("请输⼊报数值:");scanf("%d", &skip);cnt = 0;while(cnt <= n * skip){for(p_peo = peo , p_flag = flag ; p_peo < peo + n ; ++p_peo , ++p_flag){if(*p_flag)continue;cnt++;if(!(cnt % skip)){*p_flag = 1;printf("%c ", *p_peo);}}}printf("\n");return 0;}如有疑问请留⾔或者到本站社区交流讨论,感谢阅读,希望能帮助到⼤家,谢谢⼤家对本站的⽀持!。
c课程设计约瑟夫问题
c课程设计约瑟夫问题一、教学目标本章节的教学目标分为三个维度:知识目标、技能目标和情感态度价值观目标。
1.知识目标:通过学习约瑟夫问题,学生能够理解并掌握约瑟夫问题的基本概念、原理和解决方法。
2.技能目标:学生能够运用所学的约瑟夫问题的解决方法,解决实际问题,并能够进行简单的数学推理和分析。
3.情感态度价值观目标:通过学习约瑟夫问题,学生能够培养对数学的兴趣和好奇心,提高解决问题的能力和团队合作的精神。
二、教学内容本章节的教学内容以约瑟夫问题为核心,包括以下几个方面:1.约瑟夫问题的定义和背景介绍。
2.约瑟夫问题的解决方法,包括递归法、循环队列法和迭代法。
3.约瑟夫问题的应用场景,结合实际问题进行讲解。
4.约瑟夫问题的扩展,如约瑟夫环的生成和约瑟夫问题的变种。
三、教学方法为了激发学生的学习兴趣和主动性,本章节将采用多种教学方法:1.讲授法:通过讲解约瑟夫问题的定义、原理和解决方法,使学生掌握基本概念和知识点。
2.案例分析法:通过分析实际问题,引导学生运用所学的约瑟夫问题的解决方法,培养学生的解决问题的能力。
3.实验法:通过进行约瑟夫问题的编程实验,让学生亲手实践,加深对解决方法的理解和记忆。
四、教学资源为了支持教学内容和教学方法的实施,丰富学生的学习体验,将选择和准备以下教学资源:1.教材:选用权威、系统的教材,如《计算机科学导论》等,作为学生学习的基本依据。
2.参考书:推荐一些相关的参考书,如《算法导论》等,供学生进一步拓展学习。
3.多媒体资料:制作PPT、教学视频等多媒体资料,以图文并茂的形式呈现教学内容,提高学生的学习兴趣。
4.实验设备:准备计算机实验室,让学生能够进行约瑟夫问题的编程实验,提高实践能力。
五、教学评估本章节的评估方式包括平时表现、作业和考试三个部分,以全面、客观、公正地评估学生的学习成果。
1.平时表现:通过观察学生在课堂上的参与度、提问和回答问题的表现,了解学生的学习态度和理解程度。
约瑟夫问题C++代码
using namespace std;
struct node
{
int data;
struct node* next;
};
class joseph
{
public:
joseph(); //构造函数
int function(); //用于实现约瑟夫问题的功能函数
private:
node* rear; //尾指针
};
joseph::joseph()
{
cout<<"请输入桌上的人数n"<<endl;
int number;
cin>>number;
while(cin.fail()) //判断输入类型是否匹配
{
cout<<"请输入大于0的数"<<endl;
cin.clear();
cin.ignore(); //若不恰当,清空流
cin>>number;
}
rear =new node;
rear ->
for(int i=number;i>0;i--)
{
s=new node;
s->data=i;
s->next=rear->next;
rear->next=s; //使用头插法进行构造
};
while(s->next!=rear) //构造完毕,删除尾节点,方便后面的操作。
cin>>b;
}
node* s=rear; //工作指针
while(s->next!=s) //终止条件
C语言的循环链表和约瑟夫环
C语言的循环链表和约瑟夫环C语言的循环链表和约瑟夫环约瑟夫问题)是一个数学的应用问题,对于学习C语言四非常挺有帮助的,下面是店铺为大家搜集整理出来的有关于C语言的循环链表和约瑟夫环,一起了解下吧!循环链表的实现单链表只有向后结点,当单链表的尾链表不指向NULL,而是指向头结点时候,形成了一个环,成为单循环链表,简称循环链表。
当它是空表,向后结点就只想了自己,这也是它与单链表的主要差异,判断node->next是否等于head。
代码实现分为四部分:1. 初始化2. 插入3. 删除4. 定位寻找代码实现:1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1void ListInit(Node *pNode){int item;Node *temp,*target;cout<<"输入0完成初始化"<<endl; cin="">>item;if(!item)return ;if(!(pNode)){ //当空表的时候,head==NULLpNode = new Node ;if(!(pNode))exit(0);//未成功申请pNode->data = item;pNode->next = pNode;}else{//for(target = pNode;target->next!=pNode;target = target->next);4 15 16 17 18 19 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3temp = new Node;if(!(temp))exit(0);temp->data = item;temp->next = pNode;target->next = temp;}}}void ListInsert(Node *pNode,int i){ //参数是首节点和插入位置Node *temp;Node *target;int item;cout<<"输入您要插入的值:"<<endl; cin="">>item;if(i==1){temp = new Node;if(!temp)exit(0);temp->data = item;for(target=pNode;target->next != pNode;target = target->next);temp->next = pNode;target->next = temp;pNode = temp;}else{target = pNode;for (int j=1;j<i-1;++j) target="target-">next;temp = new Node;if(!temp)exit(0);temp->data = item;temp->next = target->next;target->next = temp;}}void ListDelete(Node *pNode,int i){Node *target,*temp;if(i==1){for(target=pNode;target->next!=pNode;target=target ->next);temp = pNode;//保存一下要删除的首节点 ,一会便于释放6 37 38 39 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5pNode = pNode->next;target->next = pNode;temp;}else{target = pNode;for(int j=1;j<i-1;++j) target="target-">next;temp = target->next;//要释放的nodetarget->next = target->next->next;temp;}}int ListSearch(Node *pNode,int elem){ //查询并返回结点所在的位置Node *target;int i=1;for(target = pNode;target->data!=elem && target->next!= pNode;++i)target = target->next;if(target->next == pNode && target->data!=elem)return 0;else return i;}</i-1;++j)></i-1;++j)></endl;></endl;>5 96 0 6 1 6 2 6 3 6 4 6 5 6 6 67 68 69 7 0 7 1 7 2 7 3 7 4 7 5 7 6 7 7 7 8 7 9 8约瑟夫问题约瑟夫环(约瑟夫问题)是一个数学的'应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。
约瑟夫问题C代码
约瑟夫问题C代码 1/*Joseph Problem2 *利⽤单循环链表解决约瑟夫问题。
3 *问题描述:将n个数链接成⼀个环,从第m个开始,每次从1计数到s时4 * 将s删除。
从下⼀个开始再次从1计数⾄s时删除s。
直到全5 * 部删除为⽌。
6 * */7 #include<stdio.h>8 #include<stdlib.h>910 typedef struct Node{11int data;12struct Node* next;13 }Node;14 typedef struct Node* LinkList;1516void CreateJosephLoop(LinkList *L,int number){17//创建Joseph环,在头结点中放⼊了元素1.18 *L = (LinkList)malloc(sizeof(struct Node));19if(!(*L)){20 printf("Error:malloc:0!\n");21 exit(1);22 }23 (*L)->next = (*L);24 (*L)->data = 1;25int i;26 LinkList new;27 LinkList tail = *L;28for(i = 1; i < number; i++){29new = (LinkList)malloc(sizeof(struct Node));30if(!new){31 printf("Error:malloc:1+i");32 exit(1);33 }34new->data = i+1;35new->next = tail->next;36 tail->next = new;37 tail = new;38 }39 }40void JosephProblem(int loopSize,int from,int stepBy){41//loopSize:Joseph环的⼤⼩42//form:从from开始43//stepBy:每次计数到stepBy时删除stepBy所指向的元素44 LinkList L;45 CreateJosephLoop(&L,loopSize);46int seekStart = 1;47while(seekStart < from){48 L = L->next;49 seekStart += 1;50 }51while(L->data != L->next->data){52int i = 1;53 LinkList temp;54for(i = 1;i < stepBy - 1; ){55 L = L->next;56 i++;57 }58 temp = L->next;59 printf("%d-->",temp->data);60 L->next = L->next->next;61 L = L->next;62free(temp);63 }64 printf("%d\n",L->data);65 }66int main(){67 JosephProblem(10,3,4);68 JosephProblem(41,1,3); 69return0;70 }。
约瑟夫问题详解(CC++)
约瑟夫问题详解(CC++)Josephus 约瑟夫问题假设n个竞赛者排成一个环形,依次顺序编号1,2,…,n。
从某个指定的第1号开始,沿环计数,每数到第m个人就让其出列,且从下一个人开始重新计数,继续进行下去。
这个过程一直进行到所有的人都出列为止。
最后出列者为优胜者。
无论是用链表实现还是用数组实现来解约瑟夫问题都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较麻烦,而且时间复杂度高达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 --> 0k+1 --> 1k+2 --> 2......k-2 --> n-2变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x 是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?变回去的公式很简单:x'=(x+k)%n如何知道(n-1)个人报数的问题的解?显然,只要知道(n-2)个人的解就行了。
(n-2)个人的解呢?当然是先求(n-3)的情况---- 这显然就是一个倒推问题!递推公式:令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]递推公式f[1]=0;f[i]=(f[i-1]+m)%i; (i>1)有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。
顺序表实现约瑟夫环的问题,C语言
顺序表实现约瑟夫环的问题,C语言计算机科学与工程学院《算法与数据结构》试验报告[一] 专业班级 10级计算机工程02 试验地点计算机大楼计工教研室学生学号 1005080222 指导教师蔡琼学生姓名肖宇博试验时间 2012-2-29试验项目算法与数据结构试验类别基础性() 设计性() 综合性(?) 其它( )(1)掌握用VC++上机调试线性表的基本方法; 试(2)掌握顺序表的存储结构以及基本运算的实现。
验目的及要求成绩评定表类别评分标准分值得分合计积极出勤、遵守纪律上机表现 30分主动完成设计任务程序代码规范、功能正确程序与报告 70分报告详实完整、体现收获备注:评阅教师:日期: 年月日计算机科学与工程学院试验内容一、实验目的和要求1、实验目的:(1)掌握用VC++上机调试线性表的基本方法;(2)掌握顺序表的存储结构以及基本运算的实现。
2、实验内容约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,m为任意一个正整数。
从第一个人开始顺时针方向自1起顺序报数,报到m时停止并且报m的人出列,再从他的下一个人开始重新从1报数,报到m时停止并且报m的人出列。
如此下去,直到所有人全部出列为止。
要求设计一个程序模拟此过程,对任意给定的m和n,求出出列编号序列。
3、实验要求:用顺序表实现。
二、设计分析根据实验要求,采用顺序表来完成本次实验。
实验中定义了两个顺序表,一个用来存储n个人的序号,另一个用来存储n个人的出队顺序及序号。
程序中充分考虑了如果出队的元素大于队列的元素个数时应该有的情况,如果出现这样的错误就提示~否则继续出队~三、源程序代码#include<stdio.h>#include<stdlib.h>#define MAXSIZE 10 // 宏替换最大值typedef struct{int data[MAXSIZE];int length;}Sqlist;void CreatList(Sqlist *&L,int a[],int n) //创建顺序表{L=(Sqlist *)malloc(sizeof(Sqlist));for(int i=0;i<n;i++){L->data[i]=a[i];}L->length=n;}void InitList(Sqlist *&L) //初始化顺序表{2 《算法与数据结构》试验报告计算机科学与工程学院L=(Sqlist *)malloc(sizeof(Sqlist));L->length=0;}void DestoryList(Sqlist *&L) //释放顺序表空间{free(L);}void josephus(Sqlist *&L) //约瑟夫环的核心代码{int t=0;int m=0;printf("请输入数到几个人出来");printf("\n");scanf("%d",&m);if(m>L->length){printf("没有这么多人呀~?(?_?)?");}else{printf("出列顺序为:");for(int q=L->length;q>=1;q--){t=(t+m-1)%q;printf("\n");printf("\t%d\t",L->data[t]);for(int j=t+1;j<=q-1;j++)L->data[j-1]=L->data[j];}printf("\n");}}void main(){Sqlist *s;InitList(s);int a[MAXSIZE];int n=0;printf("请键入要输入几个数"); printf("\n");scanf("%d",&n);for(int i=0;i<n;i++)3 《算法与数据结构》试验报告计算机科学与工程学院{a[i]=i+1;}CreatList(s,a,n);josephus(s);DestoryList(s);printf("\n");}四、测试用例(尽量覆盖所有分支) 1.当输入1,2,3,4。
循环队列之约瑟夫环问题
循环队列之约瑟夫环问题约瑟夫问题 约瑟夫环(约瑟夫问题)是⼀个数学的应⽤问题:已知n个⼈(以编号1,2,3...n分别表⽰)围坐在⼀张圆桌周围。
从编号为k的⼈开始报数,数到m的那个⼈出列;他的下⼀个⼈⼜从1开始报数,数到m的那个⼈⼜出列;依此规律重复下去,直到圆桌周围的⼈全部出列。
通常解决这类问题时我们把编号从0~n-1,最后结果+1即为原问题的解。
循环队列求解(链式)#include<stdio.h>#include<stdlib.h>//循环队列//typedef int ElemType;typedef struct QueueNode{int data;struct QueueNode *next;}QueueNode;typedef struct Queue{QueueNode *front;QueueNode *rear;}Queue;void InitQueue(Queue *q){q->front=q->rear=NULL;}void EnQueue(Queue *q , int value){QueueNode *temp=(QueueNode*)malloc(sizeof(QueueNode));temp->data=value;if(q->rear==NULL){temp->next=temp;q->rear=q->front=temp;}else{temp->next=q->rear->next;q->rear->next=temp;q->rear=temp;}}//enter a element from the tailvoid DeQueue(Queue *q, int *value){QueueNode *temp=(QueueNode*)malloc(sizeof(QueueNode)); if(q->rear==NULL){return;}// It's nullelse if(q->rear->next==q->rear){*value=q->front->data;free(q->rear);q->rear=q->front=NULL;}//It just has one nodeelse{*value=q->front->data;temp=q->front;q->front=temp->next;q->rear->next=q->front;}//more one nodefree(temp);}//delete a element from the headint main(){Queue *q=(Queue*)malloc(sizeof(Queue));int i,m,n,count,temp;printf("请输⼊⼈数n和循环要报的数m(两数之间留个空格)\n"); scanf("%d%d",&n,&m);for(i=1;i<=n;i++)EnQueue(q,i);printf("出圈序列:\n");while(q->front){ count=1;while(count<m){q->front=q->front->next;q->rear=q->rear->next;count++;}count=1;DeQueue(q,&temp);printf("%d ",temp);}putchar('\n');}简单解法#include <stdio.h>int josephus(int n, int m) {if(n == 1) {return0;}else {return (josephus(n-1, m) + m) % n;}}int main() {int n, m;while (scanf("%d", &n) == 1) {if (!n) {break;}scanf("%d", &m);int result = josephus(n, m);printf("%d\n", result+1);}return0;}。
约瑟夫问题实验报告
约瑟夫问题实验报告(文章一):约瑟夫问题数据结构实验报告中南民族大学管理学院学生实验报告实验项目: 约瑟夫问题课程名称:数据结构年级:专业:信息管理与信息系统指导教师:实验地点:管理学院综合实验室完成日期:小组成员:学年度第(一)、实验目的(1)掌握线性表表示和实现;(2)学会定义抽象数据类型;(3)学会分析问题,设计适当的解决方案;(二)、实验内容【问题描述】:编号为1,2,…,n 的n 个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自 1 开始顺序报数,报到m 时停止报数。
报m 的人出列,将他的密码作为新的m 值,从他在顺时针方向上的下一个人开始重新从1 报数,如此下去,直至所有人全部出列为止。
试设计一个程序求出出列顺序。
【基本要求】:利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。
【测试数据】:m 的初值为20;密码:3,1,7,2,4,8,4(正确的结果应为6,1,4,7,2,3,5)。
(三)、实验步骤(一)需求分析对于这个程序来说,首先要确定构造链表时所用的方法。
当数到m 时一个人就出列,也即删除这个节点,同时建立这个节点的前节点与后节点的联系。
由于是循环计数,所以才采用循环列表这个线性表方式。
程序存储结构利用单循环链表存储结构存储约瑟夫数据(即n个人的编码等),模拟约瑟夫的显示过程,按照出列的顺序显示个人的标号。
编号为1,2,?,n 的n 个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1 开始顺序报数,报到m 时停止报数。
报m 的人出列,将他的密码作为新的m 值,从他在顺时针方向上的下一个人开始重新从1 报数,如此下去,直至所有人全部出列为止。
试设计一个程序求出出列顺序。
基本要求是利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。
C语言程序设计漫谈之从“约瑟夫问题”谈起
从“约瑟夫问题”谈起约瑟夫问题是一个出现在计算机科学和数学中的问题。
在计算机编程的算法中,类似问题又称为约瑟夫环。
据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
然而Josephus 和他的朋友并不想自杀。
为避免与其他39个决定自杀的犹太人发生冲突,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行,直到仅余15个人为止。
问怎样的排法,才能使每次投入大海的都是非教徒。
【例1】约瑟夫问题。
N个人围成一圈,从某个人开始,按顺时针方向从1开始依次编号。
从编号为1的人开始顺时针“1,2,…M”报数,报到M的人退出圈子。
这样不断循环下去,圈子里的人将不断减少。
由于人的个数是有限的,因此最终会剩下一个人,该人就是优胜者。
输入N和M,输出出圈顺序。
例如,N=6、M=5,出圈的顺序是:5,4,6,2,3,1。
(1)编程思路。
为输出出圈顺序,采用一个数组来进行模拟。
定义int circle[N+1],并按circle[i]=i+1的方式赋予各元素初值。
该值代表两个含义:1)值为0,代表编号i+1的人不再圈中;2)值非0,代表圈中第i个位置的人编号为i+1。
定义变量i代表报数位置的流动,i的初值为0,代表编号为1的人的位置,i的变化方式为:i=(i+1)%(n),即0-->1-->2……->n-1 ->0-->1……。
约瑟夫问题 完整C程序代码
1)内容:约瑟夫(Joseph)问题的一种描述是:编号为1,2,..., n 的n 个人按顺时针方向围坐一圈, 每人持有一个密码(正整数)。
一开始选任一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。
报m的人出列,将它的密码作为新的m值,再从下个人开始新一轮报数,如此反复,直到剩下最后一人则为获胜者。
试设计一个程序求出出列顺序。
2)要求:利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。
3) 测试数据: n=7,7 个人的密码依次为:3,1,7,2,4,8,4 。
m的初值为20,则正确的出列顺序应为6,1,4,7,2,3,5。
完整代码:#include<stdio.h>#include<stdlib.h>struct person{int num;int order;struct person *next;};static struct person *head=NULL;struct person *CreatList(void){struct person *rear;struct person *p;int k=0;while(1){p=(struct person*)malloc(sizeof(struct person));p->order=++k;printf("\n请输入一个人所持的密码,输入0则建表结束:");scanf("%d",&p->num);if(p->num==0)break;if(head==NULL) head=p;else rear->next=p;rear=p;}if(rear!=NULL) rear->next=head;printf("\n建表结束\n");return head;}void josephus(struct person *p,int m) {int i,k;struct person* r;if(m==1)p=p->next;else{for(i=2;i<m;i++)p=p->next;}r=p->next;k=r->num;printf("%d ",k);printf("%d\n",r->order);p->next=r->next;free(r);if(p!=p->next)josephus(p->next,k);else{printf("%d ",p->num);printf("%d\n",p->order);}}void main(){int m;struct person *pos;CreatList();printf("请输入初始值m:");scanf("%d",&m);printf("密码顺序\n");pos=head;josephus(pos,m);}/* 测试数据,复制粘贴可用3172 4 8 4 0 20 */。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/*约瑟夫(Josephus)问题:n 个人围坐成一圈,从1 开始顺序编号;游戏开始,从第一个人开始由 1 到m 循环报数,报到m 的人退出圈外,问最后留下的那个人原来的序号。
[分析] 本题首先要定义一个数组,其元素个数为n。
n定义为常变量,以便定义数组。
数组元素的值标识该人是否出局,1在圈内,0出局。
值为0的元素不参加报数。
可用一个整型数k做计数器,采用倒计数,记录留下的人数。
[提示]数组是线性排列的,而人是围成圈的,用数组表示要有一种从数组尾部跳到其头部的技巧,即下标加1除以n求余数。
*/
#include<iostream>
using namespace std;
const int n=50;//参加人数可以在此修改
const int m=40;//循环报数值可以在此修改
int main(){
char jose[n];
int i,j=0,k;
for(i=0;i<n;i++) jose[i]=1;
for(k=n;k>=1;k--){
i=0;
while(1){
if(jose[j]==1){
i++;
if(i==m){
jose[j]=0;
break;
}
}
j=(j+1)%n;
}
}
cout<<"最后留下的那个人原来的序号:"<<j<<endl;
return 0;
}
注意:下面这个题目用到了枚举,我没有讲,但希望大家自己能自学。
两队选手每队5人进行一对一的比赛,甲队为A、B、C、D、E,乙队为J、K、L、M、N,经过抽签决定比赛配对名单。
规定A不和J比赛,M不和D及E比赛。
列出所有可能的比赛名单。
解:这是一个组合问题,使用穷举法。
共有5个位置,设甲队5名队员位置不变,乙队改变队员位置,进行配对。
注意第1个位置可在5个队员中任选一个,以后的位置必须扣除已选过的队员。
并扣除不能配对的情况,即得所有可能的比赛名单。
#include<iostream>
using namespace std;
int main(){
char st1[5]={'A','B','C','D','E'},st2[5]={'J','K','L','M','N'};
int i=0,j,k,l,m,n;
for(j=0;j<5;j++){//0号位
if(j==0) continue;//A选手不与选手J比赛,即st1[0]不与st2[0]比赛
for(k=0;k<5;k++){//1号位
if(k==j) continue;//剔除乙队占据0号位的选手
for(l=0;l<5;l++){//2号位
if(l==j||l==k) continue;//剔除乙队占据0、1号位的选手
for(m=0;m<5;m++){//3号位
if(m==j||m==k||m==l) continue;//剔除乙队占据0、1、2号位的选手
if(m==3) continue;//st1[3]不与st2[3]比赛,即D不与M比赛
for(n=0;n<5;n++){//4号位
if(n==j||n==k||n==l||n==m) continue;
//剔除乙队占据0、1、2、3号位的选手
if(n==3) continue;//st1[4]不与st2[3]比赛,即E不与M比赛
cout<<st1[0]<<'-'<<st2[j]<<'\t'<<st1[1]<<'-'<<st2[k]<<'\t';
cout<<st1[2]<<'-'<<st2[l]<<'\t'<<st1[3]<<'-'<<st2[m]<<'\t';
cout<<st1[4]<<'-'<<st2[n]<<endl;
i++;
}
}
}
}
}
cout<<i<<endl;
return 0;
}。