生死游戏
传说有30个旅客同乘一条船,因为严重超载,加上风浪大作,危险万分。因此船长告诉乘客们,只有将全船上一半的旅客投入海中,其余人才能幸免遇难。无奈,大家只得同意这种办法,并议定30人围成一圈,由第一个人数起,信次报数,数到第9人,便将他扔进大海中,如此循环地进行,直到剩下15个乘客为止。问哪些位置将是被扔下大海的位置。
可以把它变得通用一些:有N个人,从第一个开始数数,数到第M个人让他出局,直到第N/2为止,问哪些人将出局?(N,M,N/2均为整数)。
简单实现代码如下 :
#include<stdio.h>#include<stdlib.h>#include<string.h>struct SeqList{int num;char name[10];};void Joseph(struct SeqList*p , int length);void main(){struct SeqList *p;int length=0;printf("请输入准备参加游戏的人数:");scanf("%d",&length);p=(struct SeqList*)malloc(length*sizeof(struct SeqList));if(p==NULL){printf("内存分配错误 !");exit(1);}Joseph(p , length); }void Joseph(struct SeqList*p , int length) {int m;int j,k;char s[10];int i;printf("请输入间隔数m(m<=20):");scanf("%d",&m);while(m>20){printf("太大,请重新输入间隔数m(m<=20):");scanf("%d",&m);}//printf("\n");printf("请输入游戏者的名字:\n");getchar();for(i=0; i<length; i++){printf("第%d个人的名字:",i+1);gets(s);strcpy((p+i)->name,s);(p+i)->num=i+1;}printf("出局面的顺序如下:\n");//printf("\n");i=-1; //调整计数器for(k=1; k<=length/2; k++){j=0;while(j<m){i++;if(i==length)i=0;if((p+i)->num!=0) j++;}if(k==length/2) break;printf("%s",(p+i)->name);printf(",");(p+i)->num=0; //标识该人员已出局}//break语句跳转至此printf("%s",(p+i)->name); //输出最后一个出局者(p+i)->num=0;printf("\n");printf("生还者如下:\n");for(k=1,i=0; k<=length; k++,i++){if((p+i)->num!=0){printf("%s",(p+i)->name);printf(" ");}}printf("\n");free(p);} 其实这个可以看作一变形的约瑟夫问题,据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
约瑟夫问题是个有名的问题,这次只是引出其概念,还需要进一步学习讨论。