约瑟夫环是一个数学应用问题,已知N个人,从1开始编号,围坐一张圆桌周围,从编号K开始报数,数到M那个人出列
然后他的下一个人接着从1开始报数(注意这点很关键,需要考虑到循环报数),依次类推直到队伍中只有一个人,或者说所有
人都全部出列。
下面说的问题是和约瑟夫问题本质一样的,是一道经典C语言编程题目【大家一起做游戏】
题目描述是这样的:
幼儿园的小朋友们刚学习了如何数数,阿姨在下课时组织大家一起玩游戏。规则如下:
所有的小朋友绕成一圈,顺序排号,从第一个小朋友开始报数,凡是报到固定数字(例如 5)
的,都退出该游戏,直到只剩下一位小朋友游戏才中止。
每个小朋友都希望自己能有更多的练习数数的机会,所以都希望成为最终被留下的那位。
现在,请大家帮小朋友们计算一下,在第一次排号的时候排到第几位才能成为最终被留
下的小朋友。
输入:
小朋友的个数(<=50) 要被练习的数字
输出:
最终被留下的小朋友的序号
说明:
如“要被练习的数字”是 5,则每次数到 5 的同学要退出该游戏
熟悉数据结构的人可能第一想法是用循环链表来做,这也是一种很好的方法,但本文目的不在此,是为了记录另外一种解法
首先把问题分解为一下几个小问题,较容易思考
1. 需要考虑标记人是否还在这个圈上,即是否已经出队了,这里用一个int数组来表示,0为在,1为已出队
2. 既然人需要报数,就一定需要一个计数器,当数达到题目中要练习的数字时,就将刚报完数的人设置出队
3. 循环报数,刚开始报数的时候,我们用i(初试为1)来遍历这个数组,根据题意i是一直增大的,直到i==N(N为总的小朋友数)这时下一个i值应该是1,而不是N+1,这里用一个取模运算就很容易实现了,(N+1)%N=1,也就是当i的值大于N时,就执行i=i%N来获取正确的i值
代码:
int main(){
int n,count,N,i,test,j;//test为需练习的数字
cin>>n>>test;
int num[51]={0};
N=n;i=1;
while(n!=1){
count=0;
while(1){
if(i>N){
i=i%N;
}
if(num[i]==0){
count++;
}
if(count==test){//进行出队设置
num[i]=1;
i++;
break;
}
i++;
}
n--;
//输出每一轮哪个出队
for(j=1;j<=N;j++){
cout<<num[j]<<" ";
}
cout<<endl;
}
for(i=1;i<=N;i++){
if(num[i]==0){
cout<<i;
break;
}
}
}
测试用例: