問題描述:n個人(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人繼續從0開始報數。求勝利者的編號。
我們知道第乙個人(編號一定是m mod n-1) 出列之後,剩下的n-1個人組成了乙個新的約瑟夫環(以編號為k=m mod 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) mod n
如何知道(n-1)個人報數的問題的解?對,只要知道(n-2)個人的解就行了。(n-2)個人的解呢?當然是先求(n-3)的情況 ---- 這顯然就是乙個倒推問題!好了,思路出來了,下面寫遞推公式:
令f表示i個人玩遊戲報m退出最後勝利者的編號,最後的結果自然是f[n]
遞推公式
f[1]=0;
f=(f+m) mod i; (i>1)
有了這個公式,我們要做的就是從1-n順序算出f的數值,最後結果是f[n]。因為實際生活中編號總是從1開始,我們輸出f[n]+1
由於是逐級遞推,不需要儲存每個f,程式也是異常簡單:
c++
#include
int main()
OI養老專題02 約瑟夫問題求倖存者
如題。人數為n 1 n 30000 共k 1 k 30000 組資料,所報的數m恒為2,只要求輸出倖存者。如果你還不知道什麼是約瑟夫問題.如果直接暴力列舉,那麼時間複雜度就為o nm o n 所有資料一共o knm o kn 遇上這道題就爆掉了。那麼怎麼解決這種大資料的題呢?我們先手玩一把n個人的約...
問題 F 倖存者
時間限制 1 sec 記憶體限制 128 mb 狀態 提交 命題人 admin 題目描述 有n個人,現在他們從左往右站成一列。第i個人的位置為i,且第i個人手裡握著一把長度為l i 的大刀。指揮者統一指令,n個人一齊往左邊砍去。對於位置為i,j的兩個人 i j 如果滿足i j l j 那麼位置為i的...
倖存者偏差
二戰期間,盟軍需要對戰鬥機進行裝甲加厚,以提高生還率,但由於軍費有限,只能進行區域性公升級。那麼問題來了,究竟哪個部位最關鍵,最值得把裝甲加厚來抵禦敵方炮火呢?人們眾口不一,最後一致決定採用統計調查的方式來解決,即 仔細檢查每一駕戰鬥機返回時受到的損傷程度,計算出飛機整體的受彈狀況,然後根據大資料分...