终于完成了Josephus的C语言实现啦~~
据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决。Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
/*以下程序用来解决Josephus问题,现在只是完成了M>N的情况,2015-08-20 22:22:20*/
/*发现一个问题:数组的赋值问题:char People[N]={1};并不代表所有的元素都是1啊,要确保全都是1,务必使用char People[N]={1,1,1,1};或者采用循环给数组赋值*/
#include <stdio.h> #include <math.h> #define N 10 // #define M 3 // main(void) { char p,People[N];//1 means alive 0 means died for(p=0;p<N;p++) { People[p]=1; } int Last=N,j=0,k=0,Temp=0; if(M>N) { while(Last!=0) { j=(M%Last)-1;//需要从当前的值移动的总次数(要排除掉已经为0的元素) if(j>0) { for(k=1;k<=j;) { Temp++; //当前的值自加得到下一次的数组元素值 if(Temp>N-1) {Temp=0;} if(People[Temp]!=0) {k++;} //如果下一个元素的值为0 ,那么k就不会变化 } } else { for(k=1;k<=abs(j);) { Temp--; //当前的值自减得到下一次的数组元素值 if(Temp<0) {Temp=N-1;} if(People[Temp]!=0) {k++;} //如果下一个元素的值为0 ,那么k就不会变化 } } printf("People rank %d is died\n",Temp+1); k=Temp+1; for(k;People[k]==0;k++)//要确定下一个其实元素的值,下一个元素的值不能是0,而是第一个1 { if(k>N-1) {k=0;} //倘若k大于N-1时,就需要将k赋值为0避免溢出 } Temp=k; Last--; } } else { while(Last!=0)//N4 M2 { for(k=1;k<=M-1;) { Temp++; //当前的值自加得到下一次的数组元素值 if(Temp>N-1) {Temp=0;} if(People[Temp]!=0) {k++;} //如果下一个元素的值为0 ,那么k就不会变化 } People[Temp]=0; printf("People rank %d is died\n",Temp+1); k=Temp+1; if(k>=N) {k-=N;} for(k;People[k]==0;k++) { if(k>N-1) {k=0;} } Temp=k; k=1; Last--; } } return 0; }
注:若要改变起始位置,比如从第K个人开始,则Temp=K-1;
2020.8.24更新算法(在极米科技的笔试题中遇到了这个题目):
1 unsigned int Josephus_Round(unsigned int n) 2 { 3 unsigned int sum=2,i,j,k,start=0,index,tmp,*live=NULL; 4 live = (unsigned int *)malloc(n*sizeof(unsigned int)); 5 for(i=0;i<n;i++){ 6 *(live+i) = 1; 7 } 8 while(sum>1){ 9 for(i=0,j=0;i<3;j++){ 10 tmp = start+j; 11 if(tmp >= n){ 12 index = tmp%n; 13 }else{ 14 index = tmp; 15 } 16 if(live[index] == 1){ 17 i++; 18 } 19 } 20 live[index] = 0; 21 start = index+1>=n?0:index+1; 22 sum = 0; 23 for(i=0;i<n;i++){ 24 sum += live[i]; 25 } 26 } 27 for(i=0;i<n;i++){ 28 if(live[i] == 1){ 29 return i+1; 30 } 31 } 32 }
调用函数只需要输入总共参与到约瑟夫环游戏中的人总数即可,返回值为经过不断循环之后得到的最终结果!
转载请注明出处!感谢GISPALAB实验室的老师和同学们的帮助和支持~