题目:有编号从 1 到 n 的 n 个人坐成一圈报数,报到 m 的人出局,下一位再从 1 开始, 如此持续,直止剩下一位为止,报告此人的编号 X。输入 n, m,求出 X
题解分析:
一开始有 n 个人,报到 m 的人出局后,如果我们从刚才出局的那人的下一位开始重新从 1 开始编号,原问题就转化为了一个 n – 1 人的问题。
如下表所示:
原始编号 | 第一人出局后的编号 |
m + 1 | 1 |
m + 2 | 2 |
m + 3 | 3 |
... | ... |
m - 2 | n - 2 |
m - 1 | n - 1 |
m | 已出局 |
老的编号 i 与新编号 j 之间的关系为:i = (j + m) % n ,其中“%”为取余数运算。
显然,这个过程可以不断重复,n – 1 规模的问题可以继续转化为 n – 2 规模的问题、n – 3 规模的问题,直到最后只剩下一个人。
我们可以总结出如下递推公式:
f(n) = (f(n – 1) + m) % n, (n > 1),其中 f(n) 为当场上还有 n 个人时某个在场的人的编号
当最后只剩下一个人时,这个人的编号显然只能是 1 ,即 f(1) = 1,这时,我们可以根据上面的公式反推回去,推导出当 n 个人都在场时他的编号。
int LastNumber(int n, int m) { assert(n > 0 && m > 0); int last = 0; for (int i = 2; i <= n; ++i) { last = (last + m) % i; } return last + 1; }
剑指offer (45) 约瑟夫环问题
时间: 2024-10-11 21:11:50