有關經典約瑟夫問題的四種解法

2022-05-06 20:12:16 字數 2590 閱讀 7519

約瑟夫問題是資訊學奧賽中的一類經典且重要的題型,在平常的測試中屢屢出現。

通常題設可抽象為:一開始有 $n $個人圍成乙個圈, 從 $1 $開始順時針報數, 報出 $m $的人被踢出遊戲.。然後下乙個人再從$ 1 $開始報數,直到只剩下乙個人。

或者:曾經有個人在他身邊,然而現在只剩他乙個人。$who$  $are$  $you$$?$  $who$ $am$ $i$$?$  $why$ $am$ $i$ $here$$? $走的越來越慢,人越來越少,可終於還是只剩乙個了呢。他們圍成一圈,隨機了乙個人作為$1$號,然後逆時針依次編號。$1$號開始報數,報到 $1$,他走了;然後$2$號開始報數,$2$號報了$1$,$3$ 號報了$2$ ,於是$3$ 號也走了……每一輪都從上一次出局的下乙個人開始報數,第 $i$輪從$1$ 報到$i$ ,報 $i$的人出局。直到只剩他乙個人。卻早已不記得他自己是誰。

針對不同的資料範圍,可以存在如下幾種做法:

1. $o(nm)$

$o(nm)$的複雜度適用於$n,m$都在$30000$以內的情況,此類題型較少,例如「約瑟夫遊戲」一題,$n,m<=30000$,由於隨著遊戲的不斷進行,需要列舉的人數越少,所以複雜度實際低於$o(nm)$。演算法思路:暴力模擬即可。

#includeusing

namespace

std;

int t,n,m; bool v[1000100

];void

wk()

++num;

if(num==m)

v[pos]=1,++t,num=0

; }

++pos;

if(pos==n+1) pos=1

; }

}int

main()

暴力模擬約瑟夫問題

2.$o(n)$

$o(n)$演算法已經適用於大多數約瑟夫問題,讓$n<=1e7$的資料範圍可以被輕鬆解決,考慮以任意一人為起點,選出第$m$個人後的編號變化,設起始$id==0$,選出第$m$個人後,$id->(id+m)$,再回歸到原來的圓形,設$i$表示第$i$輪遊戲,那麼整體的公式即為$(id+m)$%$(n-i+1)$。倒序列舉即可。也可以用$dp$方式實現,或者正序列舉,將公式改變為$(id+m)$%$(i+1)$,最後答案即為$id+1$。

#include#define re register

using

namespace

std;

intt,n,ans,m;

inline

intread()

signed main()

for(re int i=n;i>=1;--i)

ans=(ans+m)%(n-i+1

); printf(

"%d\n

",ans+1

); }

return0;

}

o(n)遞推約瑟夫問題

3.$o(mlogn)$

此類演算法並不常見,但由於一些毒瘤出題人緣故,針對$n<=1e9,m<=1e5$型別的資料範圍,我們不得不採用特別的遞推方式,通過打表可以發現,保持$m$不變,$n$每加一,答案在模$n$意義下加$m$,注意:此時的$n$是乙個變化的$n$,那麼可以通過對$n$的遞推處理,將$o(n)$級別的列舉,轉化為在答案值域區間上的選擇性跳躍,從而將以$n$為基礎的演算法轉向以$m$為基礎的演算法,可以處理該類毒瘤問題。

#include#define int long long

#define re register

using

namespace

std;

intt,n,m;

inline

intread()

signed main()

now=now+nxt+1

; ans=(ans+(nxt+1)*m-1)%now+1

; }

printf(

"%lld\n

",ans);

}return0;

}

o(mlogn) 基於值域的約瑟夫問題

4.$o(log_m^n)$

此類演算法極其不常見,僅適用於$n$個人圍成一圈,從$1$號開始依次報數,當報到$m$時,報$1$、$2$、…、$m-1$的人出局,下乙個人接著從$1$開始報,保證$(n-1)$是$(m-1)$的倍數,最後剩的乙個人獲勝的情況。通過打表,可以發現,$f[m^a+m+1]=m$,其餘的$f[n]$都滿足$f[n][n-m+1]$,不妨$ n=m^a+(m-1)*k(m^a

1 #include2

using

namespace

std;

3long

long

n,m;

4signed main()

約瑟夫問題

至此,通過不同的資料範圍選擇不同的演算法,一般的約瑟夫問題已經可以完全解決。

$over$

關於RMQ問題的四種解法

什麼是rmq問題 rmq range minimum maximum query 對於長度為n的陣列a,回答若干詢問rmq a,i,j i,j n 1 返回陣列a中下標在i,j範圍內的最小 大 值,也就是說,rmq問題是指求區間最值的問題。1.暴力法最簡單的方法,就是遍歷陣列直接搜尋,但是這種方式時...

經典演算法 約瑟夫環問題的三種解法

約瑟夫環問題,這是乙個很經典演算法,處理的關鍵是 偽鍊錶 問題描述 n個人圍成一圈,從第乙個人開始報數,報到m的人出圈,剩下的人繼續從1開始報數,報到m的人出圈 如此往復,直到所有人出圈。模擬此過程,輸出出圈的人的序號 在資料結構與演算法書上,這個是用鍊錶解決的。我感覺鍊錶使用起來很麻煩,並且這個用...

揹包問題 四種解法解題

分別用蠻力法 動態規劃法 回溯法和分支限界法求解0 1揹包問題。注 0 1揹包問題 給定種物品和乙個容量為的揹包,物品的重量是,其價值為,揹包問題是如何使選擇裝入揹包內的物品,使得裝入揹包中的物品的總價值最大。其中,每種物品只有全部裝入揹包或不裝入揹包兩種選擇。1 基本思想 對於有n種可選物品的0 ...