猴王問題約瑟夫環

來源:互聯網
上載者:User

標籤:des   style   class   blog   code   http   

【Joseph問題描述】
n個人(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人繼續從0開始報數。求勝利者的編號。


【求解思路】
我們知道第一個人(編號一定是m%n-1) 出列之後,剩下的n-1個人組成了一個新的約瑟夫環(以編號為k=m%n的人開始):
k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2
並且從k開始報0。
現在我們把他們的編號做一下轉換:
k --> 0
k+1 --> 1
k+2 --> 2
...
...
k-2 --> n-2
k-1 --> n-1
變換後就完完全全成為了(n-1)個人報數的子問題,假如我們知道這個子問題的解:例如x是最終的勝利者,那麼根據上面這個表把這個x變回去不剛好就是n個人情況的解嗎?!!變回去的公式很簡單,相信大家都可以推出來:x‘ =(x+k)%n
如何知道(n-1)個人報數的問題的解?對,只要知道(n-2)個人的解就行了。(n-2)個人的解呢?當然是先求(n-3)的情況 ---- 這顯然就是一個反向推算問題!好了,思路出來了,下面寫遞推公式:
令f[i]表示i個人玩遊戲報m退出最後勝利者的編號,最後的結果自然是f[n]
f[1]=0;
f[i]=(f[i-1]+m)%i; (i>1)
有了這個公式,我們要做的就是從1-n順序算出f[i]的數值,最後結果是f[n]。因為實際生活中編號總是從1開始,我們輸出f[n]+1
由於是逐級遞推,不需要儲存每個f[i],程式也是異常簡單:
int main()
{
    int n, m, i, s=0;
    scanf("%d%d", &n, &m);
    for (i=2; i <=n; i++)
        s=(s+m)%i;
    printf ("The winner is %d/n", s+1);
}


【氡馬的補充】
當n個人時,退出的一定是報到m%n-1的人(有%是因為m可能大於n,經過迴圈才能報到m),由於所有人是一個環,可以認為是從任何地方開始編號的,所以在m%n-1這個人之後的人可以認為編碼都大於他,那麼整個環的編號就是m%n-1到m%n-1+n-1(也就是m%n-1到m%n-2,實際上一個編號是m還是m+n或者m+2n都無所謂,只要最終算出來的編號對n模數就是正確的編號了。)
那此人退出後他的下一位,也就是原來報m%n這位的編號將更新為0。相應的後面的編碼都會減少m%n,所以得出公式:
f[n] - m%n = f[n-1]
變形一下公式也就是:
f[n] = (f[n-1] + m) % n

 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/RadonMar/archive/2009/07/14/4346204.aspx

 

 

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

遞迴的力量:最佳化到O(N)

在Donald E. Knuth的《具體數學》中,對m=2的情況使用了遞迴的解決方案,並推出了一個常數運算式,使得此種情況下,演算法的複雜度為常量。同時,這種思路也可以應用於n>2 的情況,但無法得出常數運算式,推廣後的遞迴演算法具體的思路如下:

當n個人圍成一圈並以m為步長第一次報數時,第m個人出列,此時就又組成了一個新的,人數為n-1的約瑟夫環,要求n個人的約瑟夫環問題的解,就依賴於求n-1個人的約瑟夫問題的解,要求n-2個人的約瑟夫問題的解,則依賴於求n-2個人的約瑟夫換問題的解,依次類推,直至求1個人的時候,該問題的解。

讓我們回到問題的原始描述中,m是一個固定的值,即步長;n為一個圈的總人數,k為這個圈第一個報數的人的編號,顯然,n在每次遞迴過程中會減1,而k則可以由m,n來唯一確定,這樣的話,當n=1的時候,我們所確定的當前的k值,就是我們所要求的解。

那麼,我們可列出如下的遞迴式:

P(n, m, k)=1 (i = 1)

P(n, m, k)=(P(i - 1, m, k ) + m - 1) % n + 1; (i > 1)

(此處m需先減1是為了讓模n的值不為0)

這樣,我們可以很輕鬆的將此演算法具體實現。這裡給出它的遞推標記法以方便進下一步討論(C言描述):

 

long Josephus(long n,long m,long k){     //參數分別為:人數,出圈步長,起使報數位置,
    for (long i = 1; i <= n; i++)
        k = (k + m - 1) % i + 1; 
    return k; //返回最後一人的位置
}

 

顯然,這個演算法的複雜度僅為O(n),相比類比演算法,有了很大的改進。

再最佳化:與人數無關
上面的演算法相比最初的類比演算法效率已經大大提升了,那麼,該演算法還有改進的餘地嗎?
事實上,如果我們觀察上述演算法中的變數k,他的初始值為第一個出圈人的編號,但在迴圈的過程中,我們會發現它常常處在一種等差遞增的狀態,我來看這個式子:k = (k + m - 1) % i + 1,可以看出,當i比較大而k+m-1比較小的時候,k就處於一種等差遞增的狀態,這個等差遞增的過程並不是必須的,可以跳過。
我們設一中間變數x,列出如下等式:
k + m * x – 1 = i + x
解出x,令k = k + m * x,將i + x直接賦值給 i,這樣就跳過了中間共x重的迴圈,從而節省了等差遞增的時間開銷。
可是其中求出來的x + i可能會超過n,這樣的結果事實上已經告訴我們此時可以直接結束演算法了,即:
k = k + m * (n - i) ;
i = n;
結束。
另外對於m = 1的情況可以單獨討論:
當k == 1時,最終結果就是n;
當k != 1時,最終結果就是(k + n - 1) % n。
整個演算法的C語言描述如下:

 

long Josephus( long n, long m, long k ){ //分別為:人數,出圈步長,起使報數位置, 
    if (m == 1)
        k = k == 1 ? n : (k + n - 1) % n;
            else{
                for (long i = 1; i <= n; i++){
                    if ((k + m) < i){
                        x = (i - k + 1) / (m - 1) - 1;
                        if (i + x < n){
                            i = i + x;
                            k = (k + m * x);
                        }
                        else{
                            k = k + m * (n - i) ;
                            i = n;
                        } 
                   }
                   k = (k + m - 1) % i + 1;
               }
          }
     return k; //返回最後一人的位置
}


該演算法的演算法複雜度在m<n時已經與一個圈中的人數n沒有關係了,即使在n=2000000000,m=3,k=1的情況下,也只做了54次迴圈,事實上,大多數的情況都是m<n,且m相對來說很小,此時,這個演算法的複雜度僅為O(m);但當而m>=n時,用方程求出的值不能減少迴圈重數,演算法複雜度仍為O(n)。

 

解答約瑟夫環問題的幾個方法 問題描述:約瑟夫環
 有編號從1到N的N個人坐成一圈報數,報到M的人出局,下一位再從1開始, 如此持續,直止剩下一位為止,報告此人的編號X。輸入N,M,求出X。
常規的解法:用所有的元素產生一個迴圈鏈表,第一次從第一個向前走M步,將當前元素分離出鏈表,然後從下一個元素開始走M步,再將當前元素分離出鏈表,重複以上過程,直到鏈表中只有一個元素時即為所求.
遞迴的解法:
1int f(int n, int m)
2{
3  if (n > 1)
4    return (m + f(n - 1, m)) % m;
5  else
6    return 0;
7}
8非遞迴的解法,很巧妙:
1int f(int n, int m)
2{
3    int i, r = 0;
4    for (i = 2; i <= n; i++)
5        r = (r + m) % i;
6    return r+1;
7}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.