#先描述一下这题目的由来
- 在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中
- 39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式
- 41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀
- 然后再由下一个让重新报数,直到所有人都自杀身亡为止
- 他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
#数组方法
#include<iostream>//数组解决约瑟夫环问题;
using namespace std;
int main(){
int n,m,a[100]={0},i=0,cnt,k=0;
cin>>n>>m;
while(cnt!=(n-1))
{
i++;
if(i>n) i=1;//将首尾连接起来
if(a[i]==0){
k++;//开始报数
if(k==m){
a[i]=1;//报到三时就让这个人消失
k=0;//重新开始下一次报数
cnt++;//消失人数加一
}
}
}
for(int j=1;j<n+1;j++)
if(a[j]==0)
cout<<j<<" ";//输出最后一存活的人编号
return 0;
}
链表方法
代码
#include<iostream>
using namespace std;
//用链表实现约瑟夫环问题 (循环链表)
typedef struct node //typedef用来重命名struct node这种数据类型,将其命名为Node,注意Node与node不一样
{
int data;
struct node* next;
}Node;
void ysflb(int N,int M) //总共有N个人,报到数字为M的人出局
{
//初始化循环链表
Node *head = NULL,*p=NULL,*r=NULL; //head为头指针,指向链表的第一个结点,一开始赋值为NULL,代表不指向任何结点
head = (Node*)malloc(sizeof(Node)); //让head指向一个实际的空间
if(NULL==head) //内存空间可能会申请失败,大多数情况不会申请失败
{
cout<<"Failed!";
return;//如果失败,就中止
}
head->data=1; //从1开始编号
head->next=NULL; //一开始整个链表只有一个Node(结点),这个Node有两个域,分别是data和next
//data从1开始,next指向NULL,总共需要N个结点,现在创建了一个,还需要N-1个
p=head; //head要保持不能改变,才能够找到链表的起始位置,一开始p也指向第一个结点
//p等一下会被使用,用它可以便于创建剩下的N-1个结点
for(int i=2;i<=N;i++)
{
r=(Node*)malloc(sizeof(Node));
r->data=i;
r->next=NULL;
//插入结点
p->next=r;
p=r;
}
//创建循环链表
p->next=head; //最后一个结点的next指向头结点
p=head; //为后续方便,将p指向头结点
cout<<"淘汰的顺序:"<<endl;
//约瑟夫环的模拟
while(p->next->next!= p) //如果p的next=p,说明目前只有一个元素
{
for(int i=1;i<M;i++) //报到数字为M的时候出局
{
r=p; //保留出局的前一个结点
p=p->next; //p指向的是要出局的这个结点,需要保留前一个结点
}
// 输出
cout<<p->data<<" ";
r->next=p->next;
p=p->next; //更新p重新进行报数
}
cout<<endl<<"剩下来的人的编号:"<<endl;
cout<<r->data<<" "<<p->data; //r是倒数第二个,p是倒数第一个
}
int main()
{
int a,b;
cin>>a>>b;
ysflb(a,b);
return 0;
}
链表小知识
p->next=q;//p后面跟上q
p=q->next;//将q的下一个节点给p
p->next=q-next;//让p的节点指向q节点的下一个数据,即跳过q节点
怎么理解呢