1. 程式人生 > >聽說你還不懂約瑟夫環!!!

聽說你還不懂約瑟夫環!!!

**約瑟夫環** 問題: N個人編號為1,2,……,N,圍成一個環,依次報數,每報到M時,殺掉那個人,求最後勝利者的編號。 換一下編號,現在假設有10個人編號為a,b,c,d,e,f,g,h,i,j,M=3吧。 ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aaef0a43c46a4ccfb9f298b3ff49b96f~tplv-k3u1fbpfcp-zoom-1.image) 殺第一個人的結果如下 ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/983001be2d38477cb27624362c4ab2d7~tplv-k3u1fbpfcp-zoom-1.image) 殺第二個人的時候相當於從d開始,結果如下 ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/20f3be9276414375996c547278df0dc0~tplv-k3u1fbpfcp-zoom-1.image) 最後我們可以知道d最終存活了下來,設f(n) = x 表示有n個人時存活下來的是x,這裡f(10)=d。 現在我們來跟蹤一下d的位置變化 一開始殺第一個人時d的位置 ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bf94c01d6d394aaaa19d81ab99ddefd3~tplv-k3u1fbpfcp-zoom-1.image) 然後殺第二個人時d的位置 ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/40cb43aa93d54bac8db6a220467e3791~tplv-k3u1fbpfcp-zoom-1.image) 看到這裡我想你應該什麼都看不出來,如果我此時問你如果只有9個人那麼那個人存活的下標是多少你應該也是看不出來的。 這裡不是說大家笨,大家都是這樣子,一開始誰能反映的過來的啊。不用急聽我細細道來。 再看一下這個圖 ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/40cb43aa93d54bac8db6a220467e3791~tplv-k3u1fbpfcp-zoom-1.image) 我們很容易就可以得知最後一個是一個死人,死人是不會再被數一次的,那我們就把最後一個死人刪掉吧。 那此時不就相當於只有9個人的情況嗎 ![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e4f128b94cdf40dc90ae4ae0437e2546~tplv-k3u1fbpfcp-zoom-1.image) 雖然字母順序對不上,但是如果只看下標的話你應該能夠說出9個人的時候下標是多少的人存活下來吧也就是下標為0。 而且這個下標不是隨便來的,而是按照一定的規律出現的,也就是f(9) = f(10) - M,可能有人會問如果下標越界了咋辦啊。那還不簡單取模不就可以了。f(n)有可能會是負數,負數取模可能比較抽象,那我們轉換成正數取模吧(這一步是比較順理成章的希望沒有把你困擾住) 也就是 f(10) = f(9)+M , 為了預防越界也就是f(10) = (f(9)+M) %10; 為什麼是和10取模而不是和9取模呢?這一點的是因為9個人時是由10個人通過移位再去掉最後一個死人後得到的本質上還是10個人,自然就是要和10取模,也可以通過上面的圖,更好的理解這一點。 通過這個例子,想必你能夠簡單的寫出遞迴式子了吧,也就是f(n) = (f(n-1)+M)%n。 全過程如下 ![](https://img2020.cnblogs.com/blog/2046667/202010/2046667-20201001131153556-1595065769.png) 程式碼很簡單 ``` public int f(int n,int m){ if(n==1) return 0; return (f(n-1,m)+m)%n; } ``` 當然這題還有其他解法,陣列法和連結串列法,這些思維量就少一些了。 如果覺得有收穫,不妨花個幾秒鐘點個贊,歡迎關注我的公眾號玩**程式設計地碼農**,目前專注寫資料結構與**演算法**和計算機基礎等相關