约瑟夫斯序列

2022-09-04 03:24:25

描述:有人站在一个圈子里等待被处决。计数从圆圈中的某个点开始,并沿固定方向绕圆圈进行。在每个步骤中,跳过一定数量的人,并执行下一个人。消除工作围绕着圆圈进行(随着被处决的人被移除,圆圈变得越来越小),直到只剩下最后一个人,他们被赋予了自由。

我用谷歌搜索了这个“约瑟夫斯问题”,维基百科的点击给了我一个动态编程解决方案:,但这只会产生最后一个幸存者。我如何获得被处决人员的顺序?假设 p(5, 3) = {3,1,5,2,4}。f(n,k)=((f(n-1,k)+k-1) mod n)+1, with f(1,k)=1

另外,是否有解决方案而不是解决方案?O(nlogn)O(nk)


答案 1

要获得被处决者和最后幸存者的顺序,您只需要从头开始模拟整个过程即可。鉴于程序的描述,这将是相当容易的任务。你提出的公式只是检查谁会生存下来并快速获得答案的捷径。

有关如何使用范围树在O(n log n)中执行此操作的说明如下:http://pl.scribd.com/doc/3567390/Rank-Trees

更详细的分析可以在这里找到:http://www.imt.ro/romjist/Volum12/Number12_1/pdf/02-MCosulschi.pdf


答案 2

表示人的最自然的数据结构是循环缓冲区。我的解决方案创建一个链接列表,将列表的尾部绑回头部,然后围绕缓冲区重复计数到下一个要执行的人,从缓冲区中删除该人,并继续直到缓冲区的尾部指向自身。

(define (cycle xs)
  (set-cdr! (last-pair xs) xs) xs)

(define (josephus n m)
  (let loop ((k (- m 1)) (alive (cycle (range 0 n))) (dead '()))
    (cond ((= (car alive) (cadr alive))
            (reverse (cons (car alive) dead)))
          ((= k 1)
            (let ((dead (cons (cadr alive) dead)))
              (set-cdr! alive (cddr alive))
              (loop (- m 1) (cdr alive) dead)))

例如:

> (josephus 41 3)
(2 5 8 11 14 17 20 23 26 29 32 35 38 0 4 9 13 18 22 27 31 36
40 6 12 19 25 33 39 7 16 28 37 10 24 1 21 3 34 15 30)

您可以在我的博客上阅读更全面的解释,其中给出了三种不同的解决方案。或者,您可以在 http://programmingpraxis.codepad.org/RMwrace2 运行该程序。