题目:
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
输出自杀序号。
方法一:通过数组解决
#include<stdio.h>
void process(int a[],int n,int k)
{
int pos=0,num=1,h=0;//pos 数组a的下标
int out=0;
while(out<n)
{
pos=1+pos%n;//控制循环 (我觉得这条语句很重要,是让数组变成“环”的重点)
if(num==k&&a[pos]==0)//活着并且报k的
{
a[pos]=1;//出局
out++;
num=1;//重新报数
h++;
printf("%2d ",pos);//自杀
if(h%10==0)
printf("\n");//h其实没啥用,就是控制换行
}
if(a[pos]==0)//活着并且没有报k的
{
num++;
}
}
}
int main()
{
int n,k;
int arr[100]={0};
printf("请输入总人数:");
scanf("%d",&n);
printf("请输入报数:");
scanf("%d",&k);//为了函数的通用性,这里就输入总人数和报数(放到题中也就是n=41,k=3)
process(arr,n,k);
return 0;
}
结果如下图
方法二:环状链表
#include <stdio.h>
#include <malloc.h>
struct node
{
int num;
struct node* next;
};
//之前有些过环状链表如何创建,其实就是创建单向链表,然后头尾相连就好
//如果不太明白可以看看我的上一篇
struct node*create(int n)//创建含有n个节点的环状链表
{
int i=0;
struct node*head=NULL;
struct node*q=NULL;
head=(struct node*)malloc(sizeof(struct node));
head->next=NULL;
head->num=i+1;
if(head==NULL)
printf("NULL");
struct node*tail=head;
for(i=1;i<n;i++)
{
q=(struct node*)malloc(sizeof(struct node));
q->num=i+1;
q->next=NULL;
tail->next=q;
tail=q;
}
tail->next=head;
return (head);
}
int main()
{
int n,k,out=0,h=0;
scanf("%d %d",&n,&k);
//同样的,为了通用性我们输入n=41,k=3
struct node* head=create(n),*p=head,*t;
struct node* q=head;
int num = 1;
while(p->next!=p)//如果链表只剩下p这一个节点(也就是p指向p自身)的时候跳出循环
{
if (num<k)//如果还没报到k
{
q=p;//让q标记p目前的位置
p=p->next;//让q向后指一个(现在就是q的下一个就是p)
num++;//没自杀就正常报数咯
}
if(num==k)//报到k了,要自杀了TAT
{
out++;//自杀人数+1
num=1;//下一个重新报数
printf("%2d ",p->num);//输出可怜人的序号
h++;//这三行没啥用,是控制换行的,为了让输出好看一点
if(h%10==0)
putchar('\n');
t=p;//现在让t标记住这个p的位置(t、p指向的是同一个节点)
p=p->next;//p向后指一个
q->next=t;
q->next=t->next;
//所以目前为止的位置关系是:q->t->p(t的位置是要删除的)
free(t);//去掉t这个节点
}
}
printf("%d ",p->num);//由于循环是在最后还剩下一个节点的时候结束的,所以我们还要输出最后一个节点
return 0;
}
结果如下:(是一样der)