問題:有n個人站成環 從1開始報數,報k的人去死,之后下一個人報1,問當你是第幾個的時候可以活下來?
這篇文章主要是講解 f(n,k)=(f(n-1,k)+k)%n 這個公式是什么意思為什么是對的
雖然公式是使用數學解法 但開始時我會手動的模擬過程 其是有意義的 十分有助於理解
首先我們看樣一個問題
n=2, k=3
a b
我們首先使用人力來數 a b a 很好 a死
接下來在試一遍 n=2 k=4
a b
人力:a b a b 很好b死
n=2 k=5
人力 a b a b a 很好a死
n=2 k=9999999
人力:T_T
對於 a b 數到k死 其實用k%2就可以很快的知道誰會死了
為什么?
a b
設k=9 ab一共有兩個 所以 9%2=1 意思就是abab的數,數完最后一次完整的循環后又數了1個(數到了a) 這正是取模%的意義
現在我們還是用手動模擬 n=11 k=3
這次不用字母而是用數字編號以直接返回生存者的編號(劇透 注意分別 第幾個和編號的不同)
1 2 3 4 5 6 7 8 9 10 11
第1個死去的 k%n 即 3%11=3 第三個死去 因為我們從死去的下一個開始重新數1 也就是說 死去的下個(編號4)是新的環的開始 死去的上個(編號3)是新的環的結束
4 5 6 7 8 9 10 11 1 2 (這就是新的環)
規則就是這樣 下面我會直接寫到生存者出現
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 1 | 2 | |
7 | 8 | 9 | 10 | 11 | 1 | 2 | 4 | 5 | ||
10 | 11 | 1 | 2 | 4 | 5 | 7 | 8 | |||
2 | 4 | 5 | 7 | 8 | 10 | 11 | ||||
7 | 8 | 10 | 11 | 2 | 4 | |||||
11 | 2 | 4 | 7 | 8 | ||||||
7 | 8 | 11 | 2 | |||||||
2 | 7 | 8 | ||||||||
2 | 7 | |||||||||
7 |
當當最后的幸存者是7
------完結撒花------
f(n,k)=(f(n-1,k)+k)%n這個公式到底描述的是什么呢?(怎么用?)
將上面表格的每一行看成數組 這個公式描述的是下一輪幸存者在這一輪的下標位置
f(n,k)求得值是 有n個人 數k死最后幸存的人的下標位置是幾
這很明顯是個遞歸的式子 需要從底到上的運算
最底端是 f(1,k) f(1,k)=0 就是說只有一個人的時候幸存者的下標是0(廢話--) 編號是7
向上
f(2,k) =(f(1,k)+k)%n 在n=11 k=3是 f(2,3)=(f(1,3)+3)%2=3%2=1
在只剩兩個人時 幸存者在這一輪數組中的下標位置是1 (看看上面的表格 下標位置為1 編號是7 )
向上
f(3,3)=(f(2,3)+3)%3=4%3=1
在只剩三個人時 幸存者在這一輪數組中的下標位置是1 (看看上面的表格 下標位置為1 編號是7 )
f(4,3)=(f(3,3)+3)%4=4%4=0
在只剩三個人時 幸存者在這一輪數組中的下標位置是0 (看看上面的表格 下標位置為0 編號是7 )
.
.
f(11,3)=(f(10,3)+3)%11=6%11=6 (看看上面的表格第一行 下標位置為6 編號是7 )
我們很容易可以根據式子寫
1 int p=0;//結果 2 for(int i=2;i<=n;i++) 3 { 4 p=(p+k)%i; 5 }
p就是我們要求的第一輪的生存者的下標
而在第一輪中沒有人死去(淚目..) 編號與下標的關系是編號=下標+1(數組從0開始存儲)
所以完整的函數代碼是
int cir(int n,int k) { int p=0; for(int i=2;i<=n;i++) { p=(p+k)%i; } return p+1; }
那么這個公式為什么是正確的呢?
當我們殺死一個一個人 並形成一個新環時 實質上是掉這個人並把整個環向前移動k位
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
第一輪去掉3
1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
們從死去的下一個開始重新數1 也就是說 死去的下個(編號4)是新的環的開始 死去的上個(編號3)是新的環的結束 就是把編號4前移k(3)格使他成為新環開始
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |||||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 1 | 2 | 3 | ||||||
讓我們在重申一遍f(n,k)=(f(n-1,k)+k)%n描述的是下標位置的變化
編號1的下標位置是0 0前移3格 下標位置變成-3 -3+11=8 所以在n輪下標位置為0的編號1在n-1輪中的下標位置變成了8
如果也有一個公式的話大概就是 f(n-1,k)=f(n,k)-k>=0?f(n,k)-k:f(n,k)-k+n;
那么從n-1輪的下標位置推算第n輪的下標位置就很清楚了 f(n,k)=f(n-1,k)+k>=n?f(n-1,k)+k%n:f(n-1,k)+k (%n 使得f(n,k)取得的下標在n的范圍之內)
f(n,k)=(f(n-1,k)+k)%n
以上
重點在於f(n,k)描述的是下標位置的變化