C 语言实例 - 约瑟夫生者死者小游戏
30 个人在一条船上,超载,需要 15 人下船。
于是人们排成一队,排队的位置即为他们的编号。
报数,从 1 开始,数到 9 的人下船。
如此循环,直到船上仅剩 15 人为止,问都有哪些编号的人下船了呢?
实例
#include<stdio.h>
int c = 0;
int i = 1;
int j = 0;
int a[30] = { 0 };
int b[30] = { 0 };
int main()
{
while (i<=31)
{
if (i == 31)
{
i = 1;
}
else if (c == 15)
{
break;
}
else
{
if (b[i] != 0)
{
i++;
continue;
}
else
{
j++;
if (j != 9)
{
i++;
continue;
}
else
{
b[i] = 1;
a[i] = j;
j = 0;
printf("第%d号下船了\n", i);
i++;
c++;
}
}
}
}
}
执行以上实例,输出结果为:
第9号下船了 第18号下船了 第27号下船了 第6号下船了 第16号下船了 第26号下船了 第7号下船了 第19号下船了 第30号下船了 第12号下船了 第24号下船了 第8号下船了 第22号下船了 第5号下船了 第23号下船了

文人墨客
先确定哪个位置的人会报出 9,找到之后下一次跳过此人,直至人数等于 15。
#include<stdio.h> int main() { int i= 1; //绝对位置参数,代表当前的真实位置 int size = 30; //总人数 int b = 1; //当前的报数,或者说相对位置,每循环一次都加1,至多为9 int flag[30]; //记录数组,记录当前位置是否已选,已选记为1 for(int j = 0 ; j < 30 ; j++) { flag[j] = 0; //记录数组初始化为0 } int num[30]; //位置数组 for(int j = 0 ; j < 30 ; j++) { num[j] = j+1; //位置数组初始化 } while(size >15) //15人下船,因此人数大于15时才执行 { if(i == 31) //30即为最后一个人,下一轮要从头开始,因此30的下一个31实际是第1 i = 1; if(b == 10) //以9为循环,报数到9,下一个10改报1 b = 1; if(flag[i] == 1) //判断之前是否已经报过9 { b--; //跳过之前被选的人 //举例说明:第一轮筛选,9这个位置被选了,并通过flag[8]记录9这里已选。在第二轮筛选时就需要跳过9这里,假设第二轮第8个位置报数是1,第9个位置跳过,则第10个位置的报数为2。 //而每次循环b都自加,所以9这里b自减,保证位置10的b值正确,其他位置同理 } if(b == 9) //若当前报数为9 { flag[i] = 1; //标记此人已经报出过9 printf("%d\n" , num[i-1]); //打印报数为 9 的人的绝对位置 size--; //找到一个人,总人数减1 } i++; //绝对位置自加 b++; //报数自加 } }文人墨客
用一种比较复杂的方式解决。
前面的用的方法都比较简单,可惜我没想到,我一上来就想的是用循环链表。
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> typedef struct num{ int num; struct num * next; }student ; int main() { int i,j; student* head = NULL; student* tail = NULL ; student* p = NULL; student* q = NULL; student *temp; bool ishead = true; for(i=1;i<31;i++) { student *people = malloc(sizeof(student)); people->num=i; if(ishead){ head = people; head ->next = NULL; tail = people; ishead = false; } else { tail->next = people; tail = people; } } if(NULL!=tail || NULL == tail) tail ->next = head; i=30; p=head; q=head; while(i>15) { for(j=1;j<10;j++) { //printf(" now the num %d \n",p->num); if(j==9) { printf("the num %d get off \n",p->num); i--; q->next = p->next; free(p); p=q->next; } else{ q=p; p=p->next; } } } return 0; }文人墨客
#include <stdio.h> int main() { int arr[30]; //创建30的数组,值全部为1 for(int i = 0;i<30;i++){ arr[i]=1; } int nowP = -1; //当前报出的数,-1 开始因为 while 一开始就要 ++ int callTime = 0; //当前共有几个人下船,即完成了几次0-8(1-9)的报数 int realP = -1; //当前报数的人的真是位置 while(callTime!=15){ //只要下船人数没达到15 即一只报数 realP++; //开始记录当前哪个位置在报 if(realP == 30)realP = 0; //如果当前该坐标为30的人,即第"31"个人报,马上切换到第0个人开始报 if(arr[realP] != 0)nowP++; //如果当前人的状态不是0,即仍在船上,就记录一次报数。 if(nowP == 8){ //如果报到的数字为8,即第九人,则下船人数+1 callTime++; arr[realP] = 0; //1改为0,标记为已下船 nowP = -1; //重置nowP,下一个人继续从0报 printf("Number %d is out.\n",realP+1); //输出当前下船的人 } } return 0; }文人墨客
我认为用一个数组完成这个算法更好理解。
#include<stdio.h> int main(){ int count=0,//记录下船的人数 ,到15就终止程序 a[30]={0},//储存30人信息,0代表在船上,1代表下船了 i=0,//循环索引 c=0;// 记录报数号码,到9就清零,由下一位重新报数 while(1) { if(a[i]==0)c++;//记录报数号码 if(c==9){ count++;//下船人数加一 a[i]=1; //标记这个人下船了 printf("第%d号下船了。\n",i+1); c=0;//到9就清零,由下一位从0重新报数 } if(count==15)break;//下船的人数到15就终止程序 i++;//分析下一个人 if(i==30)i=0; //将数组变成一个圈,循环往复 } return 0; }