传说,著名犹大历史学家Josphus曾讲过一个故事:
在罗马人占领乔塔帕特后,40个犹太人与Josphus躲到一个洞中。40个犹大人决定宁愿死也不要被敌人逮到,于是决定了一个自杀方式:41个人排成一个圆圈,由第1个人开始报数,每报数到3,该人就必须自杀,然后再由下一个人重新报数,直到所有人都自杀身亡为止。
然而,Josphus并不想遵从自杀,于是他先假装同意该方案,然后坐到大家围成圆圈的第31个位置,逃过了这场死亡游戏。
问:如何确定坐在哪个位置上可以逃脱呢?
#include
#include
#include
using namespace std;
#define N 41 //总人数
#define M 3 //数到3出列
typedef struct {
int num; // 座位序号
char name[20];
int count; // 出列序号
}Josephus;
int main()
{
Josephus man[N]; //保存出列的序号,为0表示未出列
int counter=1; //出列记数器
int i=0; //报数记数器
int pos=-1; //位置记数器
for(i=0;iN-1)
printf("\n初始序号:%d,约瑟夫环序号:%d\n",man[i].num ,man[i].count );
printf("\n");
getchar();
return 0;
}
#include
#include
#include
#define N 5 //总人数
#define M 3 //数到3出列
typedef struct {
int num; // 座位序号
char name[20];
int count; // 出列序号
}Josephus;
void baoshu(Josephus man[], int n, int m) //
{
int counter=1; //出列记数器
int i=0; //报数记数器
int pos=-1; //位置记数器
while(counter<=n) //在N个人中模拟循环报数
{
do{
pos=(pos+1) % n; //求余,进行环状处理,如果记数器超过 N值,又从1开始
if(man[pos].count==0) //若编号pos还未出列
i++; //报数
if(i==m) //报数M的人
{
i=0; //初始化记数器,又从1开始报数
break;
}
}while(1);
man[pos].count=counter; //保存出列序号
counter++;
}
}
void init_Josephus(Josephus man[], int n)
{
int i;
for(i=0;i man[j].count )
{
t=man[i],man[i]=man[j],man[j]=t;
}
}
}
}
int main()
{
Josephus man[N];
init_Josephus(man,N);
baoshu(man, N, M) ;
printf("\n按座位顺序排列:\n");
display_Josephus(man,N);
sort_by_count(man,N);
printf("\n按出列顺序排列:\n");
display_Josephus(man,N);
getchar();
return 0;
}
方法3:结构体指针
直接付代码:
#include
#include
#include
#include
using namespace std;
#define N 5 //总人数
#define M 3 //数到3出列
typedef struct {
int num; // 座位序号
char name[20];
int count; // 出列序号
}Josephus;
// 模拟报数
void baoshu(Josephus *, int n, int m);
// 初始化
void init_Josephus(Josephus *, int n);
// 输出结构体数组
void display_Josephus(Josephus *, int n);
// 按出列顺序排序
void sort_by_count(Josephus *, int n);
void baoshu(Josephus *p, int n, int m) //
{
int counter=1; //出列记数器
int i=0; //报数记数器
int pos=-1; //位置记数器
while(counter<=n) //在N个人中模拟循环报数
{
do{
pos=(pos+1) % n; //求余,进行环状处理,如果记数器超过 N值,又从1开始
if(p[pos].count==0) //若编号pos还未出列
i++; //报数
if(i==m) //报数M的人
{
i=0; //初始化记数器,又从1开始报数
break;
}
}while(1);
p[pos].count=counter; //保存出列序号
counter++;
}
}
void init_Josephus(Josephus *p, int n)
{
int i;
for(i=0;inum=i+1;
gets(p->name);
p->count=0; //保存出列的序号,为0表示未出列
}
}
void display_Josephus(Josephus *p, int n)
{
int i;
printf("约瑟夫排列(最初位置--姓名--约瑟夫环位置):\n"); //输出排列位置
for(i=0;inum ,p->name , p->count );
}
}
void sort_by_count(Josephus *p, int n)
{
int i,j;
Josephus t;
for(i=0; i p[j].count )
{
t=p[i],p[i]=p[j],p[j]=t;
}
}
}
}
int main()
{
Josephus man[N];
init_Josephus(man,N);
baoshu(man, N, M) ;
printf("\n按座位顺序排列:\n");
display_Josephus(man,N);
sort_by_count(man,N);
printf("\n按出列顺序排列:\n");
display_Josephus(man,N);
getchar();
return 0;
}
方法4:循环链表
#include
#include
#include
#include
#include
using namespace std;
#define M 3 //数到3出列
typedef struct josephus{
int num; // 座位序号
char name[20];
int count; // 出列序号
struct josephus *next;
}Josephus;
int creat_link(Josephus**head){
Josephus *p,*pre;
p=pre=NULL;
int i,n=1;
char name[20];
printf("请输入要加入约瑟夫环人的姓名:(ctrl+z结束输入)");
do{
if(scanf("%s",name)==EOF)
break;
p=(Josephus*)malloc(sizeof(Josephus));
if(p==NULL){
printf("内存分配失败,退出!");
exit(1);
}
p->num=n++;
strcpy(p->name,name);
p->count=0;
if(*head==NULL){ // 循环单链表
*head=p;
p->next=p;
}
else{
p->next=pre->next;
pre->next=p;
}
pre=p;
}while(1);
return n-1;
}
void display_link(Josephus *head,int n){
Josephus *p;
int i=0;
for(p=head;inext,i++)
printf("%d %s %d\n",p->num,p->name,p->count);
}
void baoshu(Josephus *head,int n){
int counter=1; //出列记数器
int i=0,j=0; //报数记数器
Josephus *p,*pre;
printf("约瑟夫排列(最初位置--姓名--约瑟夫环位置):\n");
for(p=pre=head; counter<=n; ){ //模拟循环报数
i++;
if(i==M){// 报到3出列,删除该结点
i=0;
p->count=counter; // 出列序号
printf("%d--%s--%d\n",p->num,p->name,p->count);
pre->next=p->next;
free(p);
counter++;
}
else{
pre=p;
}
p=p->next;
}
}
int main()
{
Josephus *head=NULL;
int n;
n=creat_link(&head);
printf("\n有%d个结点。\n",n);
display_link(head,n);
printf("\n开始报数:\n",n);
baoshu(head,n);
return 0;
}
最强的来了:数学推导方法
#include
#include
using namespace std;
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);
}