约瑟夫问题
约瑟夫问题由来已久,而这个问题的解法也在不断改进,只是目前仍没有一个极其高效的算法(log 以内)解决这个问题。
问题描述
n 个人标号
。逆时针站一圈,从 号开始,每一次从当前的人逆时针数 个,然后让这个人出局。问最后剩下的人是谁。
这个经典的问题由约瑟夫于公元 1 世纪提出,尽管他当时只考虑了
过程
朴素算法
最朴素的算法莫过于直接枚举。用一个环形链表枚举删除的过程,重复
简单优化
寻找下一个人的过程可以用线段树优化。具体地,开一个
线性算法
设
这个也很好推。你从
int josephus(int n, int k) {
int res = 0;
for (int i = 1; i <= n; ++i) res = (res + k) % i;
return res;
}
对数算法
对于
考虑到我们每次走
int josephus(int n, int k) {
if (n == 1) return 0;
if (k == 1) return n - 1;
if (k > n) return (josephus(n - 1, k) + k) % n; // 线性算法
int res = josephus(n - n / k, k);
res -= n % k;
if (res < 0)
res += n; // mod n
else
res += res / (k - 1); // 还原位置
return res;
}
可以证明这个算法的复杂度是
解这个方程得到
下面我们证明该算法的复杂度是
考虑
所以
本页面主要译自博文 Задача Иосифа 与其英文翻译版 Josephus Problem。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。
贡献者:@Jimmy@F1shAndCat@mgt@FFjet@Ir1dXD@sshwy
本页面最近更新:2/3/2023, 12:00:00 AM,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用