考虑这样一个问题,有 个人,标号从 到 ,从第一个人开始数,杀死数到 的人,然后下一个人重新开始数。
问:最后死的人是几号?
假设有 个人,将没有被杀的人重新编号,那么,杀人情况如下表所示
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
11 | 12 | 13 | 14 | 15 | 16 | 17 | |||
18 | 19 | 20 | 21 | 22 | |||||
23 | 24 | 25 | |||||||
26 | 27 | ||||||||
28 | |||||||||
29 | |||||||||
30 |
第一轮杀了 号、 号和 号, 号变成了 号, 号变成了 号等等。
我们可以发现如下性质:
- 每一轮被杀的了人的编号是 的倍数,且第 个被我要的杀的人的当前轮的编号是 。
- 号被杀后,下一个被杀的人是 号,那么 号和 号是暂时安全的,因此需要对其编号,其新的编号为 和 ,因为杀完 号后相当于杀了 个人,还有 个人。
因此对于第 个被杀死的人,他死亡时编号为 ,又因为 或 ,显然 ,而上一轮的编号为 。
因此可以用下面的方法算出最后一个死的人的原编号
int J(int n) {
int i = 3 * n;
while (i > n) i = (i - n - 1) / 2 + i - n;
return i;
}
如果用 来替换 ,发现原迭代式变为
则可以用以下方法求出上面要求的结果
int J(int n) {
int i = 1;
while (i <= 2*n) i = ceil(3.0 * i / 2);
return 3*n + 1 - i;
}
当然,如果循环节的个数不为 ,而是为 ,可以用相同的方法证明,有类似的结论
int J(int n, int q) {
int i = 1;
while (i <= (q - 1) * n) d = ceil((double)q * i / (q - 1));
return q*n + 1 - i;
}
网友评论