首先简单介绍约瑟夫问题:n个人坐成一圈,给每个人编号,按顺序报数,报到m的人退出,问最后剩下人的编号是多少?
这个问题可以用模拟游戏全过程解决,不过过程会非常繁琐,各种细节也容易出问题,所以在这里考虑用数学关系解决。
通过循环从后往前推编号。
下面通过例子看每次循环后各人的编号。
n = 6;m = 3;
编号为报数-1
初始:0 1 2 3 4 5
第一次:3 4 x 0 1 2
第二次:0 1 x 2 3 x
第三次:1 2 x x 0 x
第四次:1 x x x 0 x
第五次:0 x x x x x
可以看出,旧序号为:(新序号+所报到退出的数m)%前一次还剩下的人数
定义旧序号为i,新序号为j
上一轮还剩下的人数k
i = (j+m)%k
根据上面的例子最后剩下的人到最后一轮结束后编号为1,我们从后往前推。
下面是代码实现:
#include <stdio.h>
int main()
{
int m, n;
scanf("%d%d", &m, &n);
int i,k;
i = 0;
for (k = 2;k<=n;k++)//k为上一轮剩余人数,最后一轮时即上一轮还剩2人
{
i = (i + m) % k;
}
printf("%d", i+1);
return 0;
}
我参考了下面这篇博客,其中有更详细的介绍。