数组版本
#include<stdio.h>
#include <stdlib.h>
main(){
int len;
int pace;
int time;
int start;
printf("请输入人数:\n");
scanf("%d",&len);
if(len<=0)
{
printf("输入错误,程序终止!\n");
exit(-1);
}
int *p=(int*)malloc(len*sizeof(int));
printf("请输入步长:\n");
scanf("%d",&pace);
if(pace==0)
{
printf("输入错误,重新输入!\n");
exit(-1);
}
//if(pace==0)
printf("请输入进行轮数:\n");
scanf("%d",&time);
printf("请输入您想从那个元素开始:\n");
scanf("%d",&start);
if(start==0)
{
printf("输入错误,请重新输入:\n");
exit(-1);
}
for(int i=0;i<len;i++){*(p+i) = 1;} // 数组初始化,1:表示为活着;0:表示自杀
int leftCount = len; // 计数器leftCount:计数剩下的人
int index = start-1,count = 0; // 1.数组下标index;2.循环计数器count
while(leftCount>(len-time))//从规定元素起点开始
{ // 当还剩下n个结束
if(*(p+index) == 1){
count++;
if(pace== count){ // 计数到3,1.自杀;2.循环计数器count重新开始计数;3.计数器leftCount减1
*(p+index) = 0;
count = 0;
leftCount--;
}
}
index++;
if(index == len){index = 0;} // 当到数组尾,数组下标index置零,重新开始
}
for(int j=0;j<len;j++){ // 输出结果
if(1 == *(p+j)){ printf("剩下的人为第%d个\n",j+1); }
}
}
单向循环链表版本
# include <stdio.h>
# include <stdlib.h>
typedef struct circle_list{
int data;
struct circle_list *next;
}NODE,*PNODE;//定义节点
PNODE creat_list(int len);//创建循环链表
void visit_list(PNODE mark,int len,int time);//遍历寻欢链表
PNODE kill_list(PNODE head,int pace,int time,int len,int mark);//删除循环链表的一个给定下表的元素
main()
{
int pace;//步长
int time;//轮数
int len;//循环链表的长度
int index;//开始游戏的下标
PNODE mark=NULL;//访问遍历链表的指针
PNODE head=NULL;//创建循环链表的头
int i;
printf("在罗马人占领乔塔帕特后,\n");
printf("39 个犹太人与Josephus及他的朋友躲到一个洞中,\n");
printf("39个犹太人决定宁愿死也不要被敌人抓到,\n");
printf("于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,\n");
printf("每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。\n");
printf("现在您就是约瑟夫,为了活下去,您需要预测怎样才能活到最后\n");
printf("而此时您得到了一个神奇的程序,请借助它,活下去!\n");
printf("********************************************************************************\n");
printf("欢迎来到约瑟夫问题,游戏开始!\n");
printf("请输入总人数:\n");
scanf("%d",&len);
if(len==0)
{
printf("输入错误,程序结束\n");
exit(-1);
}
head=creat_list(len);//创建链表
printf("请输入您想从第几个人开始:\n");
scanf("%d",&index);
printf("请输入步长(每经过几个人杀一个人:)\n");
scanf("%d",&pace);
printf("请输入进行的第几轮:\n");
scanf("%d",&time);
mark=kill_list(head,pace,time,len,index);//杀人并提供访问遍历链表的下标
visit_list(mark, len,time);//遍历链表
}
PNODE creat_list(int len)
{
PNODE head=NULL;
PNODE p;
PNODE q;
int i;
p=(PNODE)malloc(sizeof(NODE));
if(p==NULL)
{
printf("内存分配失败!\n");
exit(-1);
}
head=p;
p->data=1;//创建头结点 并且将它的数据域置为1
for(i=2;i<=len;i++)//创建其他节点并依次将这些节点挂在尾部
{
q=(PNODE)malloc(sizeof(NODE));
if(q==NULL)
{
printf("内存分配失败!\n");
exit(-1);
}
q->data=i;//依次给节点数据域赋值,作为“人”的序号
p->next=q;
p=q;//让p永远指向链表的尾部
}
p->next=head;//首尾相连
return head;//返回头结点地址以便访问
}
void visit_list(PNODE mark,int len,int time)//遍历循环链表
{
PNODE p=mark;//从标记开始进行循环
int count=0;
printf("幸存下来人的序号为:\n");
do
{
printf("%d ",p->data);//依次输出未被删除节点的序号
p=p->next;
}
while(p!=mark);//当没有循环够一圈
printf("\n");
}
PNODE kill_list(PNODE head,int pace,int time,int len,int index)
{
int leftcount=len;//活着的人数
PNODE p=head;
PNODE mark=NULL;//留下以便访问的地址
PNODE remain=NULL;//作为用来防止内存泄漏的媒介
int count=0;//循环次数
int count1=0;//从开始游戏的那个人开始循环次数
while(leftcount>(len-time))
{
count++;
if(count>=index)//当过了要开始下表才开始杀人
{
count1++;
if(count1%(pace-1)==0)//当循环到要删除的那个节点的上一个节点才开始删除下一个节点
{
mark=p;//不断刷新下表让它永远是最后留在链表中节点的地址即mark所指向的那个节点删到最后一定要存在
remain=p->next;
p->next=p->next->next;//改变指针指向来删除节点
free(remain);
leftcount--;//人数减少一位
}
}
p=p->next;//遍历条件
}
return mark;
}