用具體數學解決約瑟夫環問題

2021-10-19 14:22:12 字數 2800 閱讀 7529

有 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

q​d⌉

​演算法偽**:

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

q​d⌉

//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...