约瑟夫环的数学优化方法
??????? 為了討論方便,先把問題稍微改變一下,并不影響原意:問題描述:n個人(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人繼續從0開始報數。求勝利者的編號。
????? 我們知道第一個人(編號一定是(m-1)%n) 出列之后,剩下的n-1個人組成了一個新的約瑟夫環(以編號為k=m%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
???????n-1 -->?n-1-k???? 0--> n-k???
??????? ... ...
???? k-3 --> n-3 k-2 --> n-2
???? 序列1: 1, 2, 3, 4, …, n-2, n-1, n
?????序列2: 1, 2, 3, 4, … k-1, k+1, …, n-2, n-1, n
?????序列3: k+1, k+2, k+3, …, n-2, n-1, n, 1, 2, 3,…, k-2, k-1
???? 序列4:1, 2, 3, 4, …, 5, 6, 7, 8, …, n-2, n-1
????? 變換后就完完全全成為了(n-1)個人報數的子問題,假如我們知道這個子問題的解:例如x是最終的勝利者,那么根據上面這個表把這個x變回去不剛好就是n個人情況的解嗎?!!變回去的公式很簡單,相信大家都可以推出來:
?? ∵ k=m%n;
?????? ∴ x' = x+k = x+ m%n ; 而 x+ m%n 可能大于n
?????? ∴x'= (x+ m%n)%n = (x+m)%n 得到 x‘=(x+m)%n
??????? 如何知道(n-1)個人報數的問題的解?對,只要知道(n-2)個人的解就行了。(n-2)個人的解呢?當然是先求(n-3)的情況 ---- 這顯然就是一個倒推問題!好了,思路出來了,下面寫遞推公式:
????? 令f表示i個人玩游戲報m退出最后勝利者的編號,最后的結果自然是f[n].
????? 遞推公式: f[1]=0; f[i]=(f[i-1]+m)%i; (i>1)
???????完整的實現代碼如下:
/* 約瑟夫環遞推公式:令f[i]表示i個人玩游戲報m退出最后勝利者的編號,最后的結果自然是f[n] 遞推公式 f[1]=0; f[i]=(f[i-1]+m)%i; (i>1) */ #include "stdio.h" #include "stdlib.h" int main(void) {int n, m,i, f[20]={0};scanf("%d %d",&n,&m);for(i=2;i<=n;i++){f[i]=(f[i-1]+m)%i;printf("%d個人報數,報到%d的出列,最后的勝者下標為%d\n", i,m,f[i]);}printf("The winner is %d\n", f[n]+1);system("pause"); }?????? 優化后的代碼為:
#include "stdio.h" #include "stdlib.h" int main(void) {int n, m,i, s=0;scanf("%d %d",&n,&m);for(i=2;i<=n;i++){s=(s+m)%i;}printf("The winner is %d\n", s+1);system("pause"); }
?
總結
以上是生活随笔為你收集整理的约瑟夫环的数学优化方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 四道面试题
- 下一篇: 程序员面试100题之一:对称字符串的最大