約瑟夫環的數學解法


    CSDN鏈接 

    問題描述:已知n個人(以編號1,2,3...n分別表示)圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列;他的下一個人又從1開始報數,數到m的那個人又出列;依此規律重復下去,直到圓桌周圍的人全部出列。求最后剩下的人的初始編號。

 

    可以把問題轉換成:n個人(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人繼續從0開始報數。求勝利者的編號。則所得的解加1即為原問題的解;

      一般我們采用一個循環隊列來模擬約瑟夫環的求解過程,但是如果n比較大的時候,采用模擬的方式求解,需要大量的時間來模擬退出的過程,而且由於需要占用大量的內存空間來模擬隊列中的n個人,並不是一個很好的解法。
在大部分情況下,我們僅僅需要知道最后那個人的編號,而不是要來模擬一個這樣的過程,在這種情況下,可以考慮是否存在着一種數學公式能夠直接求出最后那個人的編號。

    我們知道第一個人(編號一定是m%n-1) 出列之后,剩下的n-1個人組成了一個新的約瑟夫環(以編號為k=m%n的人開始):
我們先看第一個人出列后的情況,顯而易見,第一個出列的人的編號一定是m%n-1,這個人出列后,剩下的n-1個人組成了一個新的約瑟夫環,這個約瑟夫環的第一個人在最開始的環中的編號是k=m%n(就是第一個出列的人的下一個)
k  k+1  k+2  ... n-2, n-1, 0, 1, 2, ... k-2並且從k開始報0。
    事實上,第一個出列的人的編號 m%n-1==k-1,在他被出列后,剩下的人又映射成為一個新的環:

   原編號   新編號
    k   ---   0
    k+1 ---   1
    k+2 ---   2
     ...  ....

   n-1  --- n-k-1

    0   ---  n-k

    1   --- n-k+1

        ...  ...

   k-3 ---   n-3

   k-2 ---  n-2

  (k-1已經被出列)

--------------------------------------------------一個循環

    可以看出,這就是原問題中把n替換成n-1的情況,設最終勝利的那個人在這種編號環境里(已經出列一個元素,編號范圍為0 ------- n-2)的編號為x,則我們可以求出這個人在原編號環境(初始編號范圍 0----n-1)下的編號(x+k)%n.

    我們用f(n)表示n個人的情況(編號環境)下的勝利者的編號,則我們要求的為f(n);

    那么如何知道n-1個人下面的這個x呢,yes,就是n-2個人情況下得到的x'倒推回去,那么如何知道n-2情況下的x'呢,當然是求n-3個人,這就是一個遞歸的過程  f(n) = (f(n-1)+m)%n.

    當最后剩下一個人(最新編號為0)的時候,無論m為幾,這個人總是勝利者,即f(1)=0;

    根據以上推理可以得到遞推式
        f(1) = 0
        f(n) = (f(n-1)+m)%n
    那么我們要求f(n),就從f(1)倒推回去即可.

(注意,我們這個算法是把編號為1---n 用 0----n-1替換的,所以最后求出來的編號+1才是最初問題的解,即f(n)+1).

  1.  int f(int n, int m)  
  2.    {  
  3.        int r = 0;//即f(1)=0;  
  4.        for(int i = 2; i <= n; i++)  
  5.            r = (r + m) % i;//即f(i)=[f(i-1)+m]%n;  
  6.        return r + 1; //即f(n)=1;  
  7.     }</span>  

 

       這種方法比模擬的方法快多了,我們在碰到問題的時候,可以想一想是否有數學公式來求解 。

       參考出處:Jackie`s blog


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM