刷題 - 約瑟夫問題 -模擬過程及簡單求解

約瑟夫問題

約瑟夫問題表述如下:假定有N個人圍成一個環,並對每個人進行順序編號,我們設定一個數字M,M<=N,從第一個人開始報數,報到M後這個人出列,剩下的人繼續從1開始報數,報到M出列,依次進行下去,直到所有的人都出列。

模擬約瑟夫全過程:

模擬約瑟夫問題的全過程,記錄出列的人的順序,模擬約瑟夫問題的方法可以用鏈表也可以用數組,在此我們用數組的方式給出模擬約瑟夫問題的過程:

假定共有N個人,我們申請一個大小爲N的數組,這個數組每個位置依次對應着編號爲1、2、3、....、N的人,則數組編號爲 i 的下一個人對應的編號爲 (i+1) % N,這裏我們要注意的是數組的下標是從0開始的,因此數組編號對應的人的編號需+1。

我們設定數組存儲的值爲0/1,首先初始化數組內的值爲0,代表數組內所有人都沒有出列,1代表該位置的人出列了。模擬約瑟夫問題的過程就是循環遍歷數組:初始化一個標誌位flag=0,從第0個人開始,每遍歷一個0,flag+1,遍歷到1,flag不變,直到flag=M時,將當前編號的人出列,即當前位置的數組置1,而後flag歸零,循環繼續,推出循環的條件時數組內0的數目爲0

給出約瑟夫問題C++代碼:

class Solution {
public:
    void Josephus(int N,int M){
        //初始化一個約瑟夫環數組,初始化0
        int* circleArray = (int*)calloc(sizeof(int),N);
        int flag = 0;//記錄約瑟夫每個子過程的計數;
        int index = 0;//當前遍歷的位置
        int alive = N;//剩餘未出列的人數,用於循環判斷
        //模擬約瑟夫過程
        while(alive>0){
            flag = flag + (1-circleArray[index]);//index位置沒有出列,flag+1,index出列,flag+0
            //達到了M,當前報數的人出列
            if(flag == M){
                circleArray[index] = 1;//出列
                flag = 0;//重新計數
                alive--;//剩餘人數-1
                //出列的人對應的真實編號未index+1
                printf("%d", index+1);
            }
            //繼續遍歷
            index = (index +1) % count;	
        }
        free(circleArray);
    }
};

模擬約瑟夫問題的全過程是一個循環遍歷的過程,隨着N和M的增大,算法複雜度爲O(NM),一種典型的約瑟夫問題不要求把出隊的全過程都給出結果,只需要給出最後一個出列的人即可。

假定1、2、3、...、N的人,編號爲0 .... N-1,設第k=M%N個人(編號爲k-1)出列後剩下的N-1個人組成了一個新的約瑟夫環,編號分別爲:

                                                k、k+1、k+2、...、N-2、N-1、0、1、2、...、k-2    (1)

對這個約瑟夫環中的數重新從0開始編號:

                                               k =》0    k+1 =》1    k+2=》2   .......      k-2 =》N-2   (2)

假定當前N-1個人對應對應的問題結果是x,則根據公式(2),如果箭頭右邊爲x,對應左邊的值爲k+x,因此結果N個人的情況的結果爲(x+k)%N = (x+M%N)%N,化簡上式爲:

                                                                                 (x+M)%N;

由此我們就得到了遞推公式:

f[1] = 0; //當一個人的時候,出隊人員編號爲0

f[n] = (f[n-1] + M)%N  //m表示每次數到該數的人出列,n表示當前序列的總人數

class Solution {
public:
    int LastRemaining_Solution(unsigned int n, unsigned int m){
        if(n==0)
            return -1;
        if(n==1)
            return 0;
        else
            return (LastRemaining_Solution(n-1,m)+m)%n;
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章