約瑟夫環/筆試題

約瑟夫問題

約瑟夫問題是個著名的問題:N個人圍成一圈,第一個人從1開始報數,報M的將被殺掉,下一個人接着從1開始報。如此反覆,最後剩下一個,求最後的勝利者。

例如只有三個人,把他們叫做A、B、C,他們圍成一圈,從A開始報數,假設報2的人被殺掉。

首先A開始報數,他報1。僥倖逃過一劫。
然後輪到B報數,他報2。非常慘,他被殺了
C接着從1開始報數
接着輪到A報數,他報2。也被殺死了。
最終勝利者是C

普通解法

藉助循環鏈表實現。
每個節點維護一個數字 和一個狀態位

到時候直接循環走就行了, 沒步計數,直剩下一個人時,繼續循環,找到那個人的編號。

複雜度分析:
一直轉圈圈走,類似於一個O(nn)的複雜度。實際上是O(nm)次

假如數據量很大的話,效率就非常差了。

看到大佬分析的公式法:

大佬的原文鏈接

我們重新定義一下題目。

拉出來的人都是倖存者。

這邊我們先把結論拋出了。之後帶領大家一步一步的理解這個公式是什麼來的。

遞推公式: f(N,M)=(f(N−1,M)+M)%N

f(N,M) 表示,N個人報數,每報到M時殺掉那個人,最終勝利者的編號
f(N−1,M)表示,N-1個人報數,每報到M時殺掉那個人,最終勝利者的編號
下面我們不用字母表示每一個人,而用數字。
1、2、3、4、5、6、7、8、9、10、11
表示11個人,他們先排成一排,假設每報到3的人被殺掉。

剛開始時,頭一個人編號是1,從他開始報數,第一輪被殺掉的是編號3的人。
編號4的人從1開始重新報數,這時候我們可以認爲編號4這個人是隊伍的頭。第二輪被殺掉的是編號6的人。
編號7的人開始重新報數,這時候我們可以認爲編號7這個人是隊伍的頭。第三輪被殺掉的是編號9的人。
……
第九輪時,編號2的人開始重新報數,這時候我們可以認爲編號2這個人是隊伍的頭。這輪被殺掉的是編號8的人。
下一個人還是編號爲2的人,他從1開始報數,不幸的是他在這輪被殺掉了。
最後的勝利者是編號爲7的人。
下圖表示這一過程(先忽視綠色的一行)

在這裏插入圖片描述

現在再來看我們遞推公式是怎麼得到的!

將上面表格的每一行看成數組,這個公式描述的是:倖存者在這一輪的下標位置

f(1,3)f(1,3):只有1個人了,那個人就是獲勝者,他的下標位置是0
f(2,3)=(f(1,3)+3)%2=3%2=1f(2,3)=(f(1,3)+3)%2=3%2=1:在有2個人的時候,勝利者的下標位置爲1
f(3,3)=(f(2,3)+3)%3=4%3=1f(3,3)=(f(2,3)+3)%3=4%3=1:在有3個人的時候,勝利者的下標位置爲1
f(4,3)=(f(3,3)+3)%4=4%4=0f(4,3)=(f(3,3)+3)%4=4%4=0:在有4個人的時候,勝利者的下標位置爲0
……
f(11,3)=6

上面這個例子驗證了這個遞推公式的確可以計算出勝利者的下標,下面將講解怎麼推導這個公式。

**問題1:**假設我們已經知道11個人時,勝利者的下標位置爲6。那下一輪10個人時,勝利者的下標位置爲多少?

答:其實吧,第一輪刪掉編號爲3的人後,之後的人都往前面移動了3位,勝利這也往前移動了3位,所以他的下標位置由6變成3。

**問題2:**假設我們已經知道10個人時,勝利者的下標位置爲3。那下一輪11個人時,勝利者的下標位置爲多少?

答:這可以看錯是上一個問題的逆過程,大家都往後移動3位,所以f(11,3)=f(10,3)+3f(11,3)=f(10,3)+3。不過有可能數組會越界,所以最後模上當前人數的個數,f(11,3)=(f(10,3)+3)%11

**問題3:**現在改爲人數改爲N,報到M時,把那個人殺掉,那麼數組是怎麼移動的?
答:每殺掉一個人,下一個人成爲頭,相當於把數組向前移動M位。若已知N-1個人時,勝利者的下標位置位f(N−1,M)f(N−1,M),則N個人的時候,就是往後移動M爲,(因爲有可能數組越界,超過的部分會被接到頭上,所以還要模N),既f(N,M)=(f(N−1,M)+M)%n

**注:理解這個遞推式的核心在於關注勝利者的下標位置是怎麼變的。**每殺掉一個人,其實就是把這個數組向前移動了M位。然後逆過來,就可以得到這個遞推式。

因爲求出的結果是數組中的下標,最終的編號還要加1

下面給出代碼實現:



//我們想法是:拿出來的人都是被殺者
//n是總人數, m是殺死編號m的人
int cir(int n,int m)
{
    int p=0;//倖存者編號
    for(int i=2;i<=n;i++)//只有1個人肯定是倖存者
    {
        p=(p+m)%i;//防止越界
    }
    return p+1;//最後一個被殺的人就是倖存者
}

2020年05-07趨勢科技筆試題

變化
m是一個變的數。從1…直到最後剩下一個人

這個時候,我們可以讓m每次自增即可。

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