有 n 個人圍成乙個圈,每 q 個人踢掉乙個人,問最後留下來的人是幾號?
使用鍊錶暴力求解時間複雜度是 o(qn),遞迴的話是 o(n) ,使用這個方法可以加速到 o(logn).
假設初始編號為1,2,3 … n ,現在考慮一種新的編號方式。
第乙個人不會被踢掉,那麼他的編號從n 開始往後加1 ,變成n+1 ,然後第二個人編號變為n+2 ,直到第q 個人,他被踢掉了。
然後第q+1 個人編號繼續加1 ,變成了n+q ,依次下去。
考慮當前踢到的人編號為kq,那麼此時已經踢掉了k 個人,所以接下去的人新的編號為n+k(q-1)+1…。
所以編號為kq+d 的人編號變成了n+k(q-1)+d ,其中1<=d;
直到最後,可以發現活下來的人編號為qn ,問題是怎麼根據這個編號推出他原來的編號?
以 n=10 , q=3 為例,下圖就是每個人新的編號:12
3456
78910
1112t13
14t1516t17
18t1920t21
22t2324t25
26t2728t29
30令:
n =n
+k(q
−1)+
d\quad n=n+k(q-1)+d
n=n+k(
q−1)
+d則他上一次的編號為:
k q+
d=kq
+n−n
−k(q
−1)=
k+n−
n\quad kq+d=kq+n-n-k(q-1)=k+n-n
kq+d=k
q+n−
n−k(
q−1)
=k+n
−n又 ∵k
=n−n
−dq−
1=⌊n
−n−1
q−1⌋
又 \because k=\frac=\left\lfloor\frac\right\rfloor
又∵k=q−
1n−n
−d=
⌊q−1
n−n−
1⌋所以他上一次的編號可以寫為:
⌊ n−
n−1q
−1⌋+
n−
n\left\lfloor\frac\right\rfloor+n-n
⌊q−1n−
n−1
⌋+n−
n因此最後存活的人可以這樣計算:
n = qn
while n > n:
n = k + n - n
ans = n
其中k 等於:
k =⌊
n−n−
1q−1
⌋k=\left\lfloor\frac\right\rfloor
k=⌊q−1
n−n−
1⌋如果用d=qn+1-n 代替n ,那麼演算法可以簡化為:
d =q
n+1−
n=qn
+1−(
⌊(qn
+1−d
)−n−
1q−1
⌋+qn
+1−d
−n)=
n+d−
[(q−
1)n−
dq−1
]=d−
⌊dq1
⌋=d+
⌈dq−
1⌉=⌈
qq−1
d⌉
\begin d=q n+1-n \\ =q n+1-\left(\left\lfloor\frac\right\rfloor+q n+1-d-n\right) \\ =n+d-\left[\frac\right] \\ =d-\left\lfloor\frac\right\rfloor \\ =d+\left\lceil\frac\right\rceil \\ =\left\lceil\frac d\right\rceil \end
d=qn+1
−n=q
n+1−
(⌊q−
1(qn
+1−d
)−n−
1⌋+
qn+1
−d−n
)=n+
d−[q
−1(q
−1)n
−d]
=d−⌊
q1d
⌋=d+
⌈q−1
d⌉=
⌈q−1
qd⌉
演算法偽**:
d = 1
while d <= (q-1)n:
d = k
ans = qn + 1 - d
其中k 等於:
k =⌈
qq−1
d⌉
k=\left\lceil\frac d\right\rceil
k=⌈q−1
qd⌉
//c++**
#include using namespace std;
typedef long long ll;
ll ceil(ll x, ll y)
ll j(ll n, ll q)
return q * n + 1 - d;
}int main()
return 0;
}
約瑟夫環問題數學解法
首先一開始的序列 序列1 1,2,3,4,n 2,n 1,n 此時出佇列的第乙個人,位置為k,號碼肯定是m n。這個應該沒有問題,也就是取餘操作使得陣列類似能夠有迴圈的功能。此時序列2 1,2,3,4,k 1,k 1,n 2,n 1,n 此時k出佇列,序列2中為n 1個人了。根據序列2,得到序列3 ...
約瑟夫環問題的數學解法
無論是用鍊錶實現還是用陣列實現都有乙個共同點 要模擬整個遊戲過程,不僅程式寫起來比較煩,而且時間複雜度高達o nm 當n,m非常大 例如上百萬,上千萬 的時候,幾乎是沒有辦法在短時間內出結果的。我們注意到原問題僅僅是要求出最後的勝利者的序號,而不是要讀者模擬整個過程。因此如果要追求效率,就要打破常規...
約瑟夫環問題的解決
約瑟夫環問題介紹 已知n個人 以編號1,2,3.n分別表示 圍坐在一張圓桌周圍。從編號為1的人開始報數,數到m的那個人出列 他的下乙個人又從1開始報數,數到m的那個人又出列 依此規律重複下去,直到圓桌周圍的人全部出列。include include include typedef int datat...