求解约瑟夫问题(Joseph Problem)的数学方法 from 御剑晨风
2011-10-17 22:39 诸葛二牛 阅读(686) 评论(0) 编辑 收藏 举报http://alexxyjiang.blog.163.com/blog/static/11713572120109210942883/
约瑟夫问题(Joseph Problem):
n个人(编号由0, 1, ..., n-1)围成一圈,由编号0的人从1开始报数,报到m的退出,剩下的人继续从1开始报数,直到圈内只剩余1人,求胜利者的编号。(n>0, m>0)
--------------------------------
求解约瑟夫问题,很容易想到的常规方法是模拟,不仅程序写起来比较烦,而且时间复杂度高达O(mn),当m,n非常大的时候,这样的时间复杂度就显得太高了。
有没有一种方法,能够降低计算的复杂度呢?答案是肯定的。
--------------------------------
我们可以通过数学推理得到这样的方法:
定义每一轮新的报数开始前后,以当前报数为1的人向正方向结合剩余的人构成的环为约瑟夫环。不失一般性,不妨设这是从(i+1)人到i人的过程(i>=0)
报数前后,分别对应着两个约瑟夫环:
报数前:0, 1, 2, 3, ..., i
报数后:0, 1, 2, 3, ..., (i-1)
这两个报数前后的环,显然是有关系的,是什么样的关系呢?
推理步骤如下:
1)在(i+1)报数到m的过程中,出列者的号码是(m-1)%(i+1),下一个报数人编号自然就是m%(i+1),不妨设为k;
2)建立报数前后的对应关系:
k ---> 0
k+1 ---> 1
k+2 ---> 2
...
k-2 ---> i-1
(要注意:k-1号在前一轮出局)
3)设在i人中,最终剩余者的编号是x,那对于(i+1)人作逆推,容易得到(i+1)人中最终剩余者的编号x'满足如下关系:
x'=(x+k)%(i+1);
4)将(3)得到的公式作完整逆推,则可以得出最终的解;
用上述数学方法构建算法时间复杂度为O(n),不需要额外空间,空间复杂度为O(1)
--------------------------------
另外要说明的是,这个方法只能在o(n)的方法内求出第任意某个出去的人的位置。如果要求出整个出去序列,用这个方法还是o(n^2)的……求所以出去序列,用线段数可以做到o(nlog(n))..貌似没有比这个快的了……