约瑟夫(Josephus)问题是由古罗马的史学家约瑟夫提出的,他参加并记录了公元66-70年犹太人反抗罗马的起义。约瑟夫作为一个将军,设法守住了裘达伯特城达47天之久,在城市沦陷之后,他和40名将士在附近的一个洞穴中避难。在哪里,将士们群情激奋并表示:要投降毋宁死。于是,约瑟夫建议每个人轮流杀死他旁边的人,而这个顺序是由抽签决定的。约瑟夫有预谋地抓到了最后一签并且做为洞穴中两个幸存者之一生存下来。约瑟夫环问题的具体描述是:设有编号为1,2,......,n的n(n>0)个人围成一个圈,从第一个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,......,如此下去,知道只剩下一人为止。当任意给定 n和 m后,设计算法求 n个人出圈的次序。
int minIndex = 0;//计数器
int quet = 0;//记录剩下的人数
int m = 0, n = 0;
printf("输入人数和循环数:");
scanf("%d%d", &m, &n);
int array[m];
int index = m;//循环次数
for ( int i = 0; i <= m ; i++) {
array[i - 1] = i;
}
while (index > 0) {
//外层循环次数大于他的人数就行,保证能循环到找到那个人
for (int i = 0; i < m; i++) {
if (array[i] != 0) {
//如果对应的值不等于0,也就是对应位置还有人参与的话,累加midIndex,也就是继续数数
minIndex ++;
}
if (minIndex == n) {
//如果数到3,则让其下标对应的人退出,(对应值归零)
array[i] = 0;
//如果累加等于3,也就是数到3的时候,累加器归零,重新数数
minIndex = 0;
}
}
//以上循环循环一次之后,会得出一组踢人之后的数组.
for (int i = 0; i < m ; i++) {
if (array[i] != 0) {//这个条件判断对应的位置是否有人,如果有人 则累加器+1
quet++;
}
}
//循环过后得到,第一次循环之后,还剩多少人
if (quet == 1) {//如果剩下一个人,则让外层循环停止 也就是 index 初始化,
index = 0;
for (int i = 0; i < m ; i++) {
if (array[i] != 0) {
printf("剩下的人是:%d",array[i]);//输出剩下的一个人
}
}
}
else if (quet != 1)//如果剩下的人不是一个,则重置quet,要不然下次循环还会累加
quet = 0;
index --;
}