POJ 1012 約瑟夫環

2021-08-21 14:19:57 字數 1540 閱讀 4962

poj的約瑟夫環問題是原本約瑟夫環的一種變形。約瑟夫環:有n個人,從第乙個人開始報數,數到第m個人就退出,依次迴圈,最後剩下的人為勝利者。可以用迴圈鍊錶和陣列的方法做,當m,n比較小時可以一試:迴圈鍊錶,數到就刪除,數到只剩乙個就輸出;陣列,第0個位置數值置為n,其他照常:a[1]=1,a[2]=2....數到就置為0,並計數,數到最後乙個就輸出。

但當n,m較大時,就需要換一種方法了,況且題目要求的是輸出勝利者的編號,這裡就不需要刪除操作了。參考了網上其他大牛的方法(試著寫一下自己的見解:題目變換一下,n個人編號範圍0-n-1,從零開始報數,報到m-1時的人退出。(為什麼從零開始呢,是為了計算方便,求位置需要用到求餘,如果從1開始,當編號為n的人要退出時,求餘的結果是0,)第一次數數,數到了第m%n - 1人,那麼,設下乙個開始的人編號為k(k=m%n),剩下的n-1個人又是乙個約瑟夫環問題,並且從k開始報0:k,k+1,k+2,k+3...n,0,1,2...k-2.我們做一下變換,k對應0,k+1對應1,k+2對應2...k-2對應n-2。這裡我們看到了遞推的思想:把大問題化成小問題,一直化簡到可以解決為止。假如我們知道n-1個人的約瑟夫環問題的解,即勝利者的編號為x,那麼,不就可以求n個人的約瑟夫環問題的解了嗎。也許你會問,這之間**有聯絡?首先我們要明白的是,編號從k-k-2的n-1個人的約瑟夫環問題的解和編號從0-n-1的n-1個人的約瑟夫環問題的解是同乙個人,但是編號不同了;而編號從k-k-2的n-1個人的約瑟夫環問題的解不就是n個人的約瑟夫環問題的解嗎,只不過我們踢掉了乙個人而已,不論踢掉多少個人,勝利者是不會變的。因此,把x的編號變回去,就是n個人的約瑟夫環問題的解了。x'=(x+k)%n,而k=m%n,求餘不論求多少次結果是一樣的,因此公式可以寫為x'=(x+m)%n。那麼n-1個人的約瑟夫環問題(編號0-n-1)的解如何知道呢,就需要求n-2個人的約瑟夫環問題(編號0-n-2),依次遞推下去,得到遞推公式:s=(s+m)%i,s從0開始,i從2開始

int n, m, i, s=0; 

scanf("%d", &n); 

scanf("%d", &m); 

for(i=2; i<=n; i++) 

s=(s+m)%i; 

printf("the winner is %d\n", s+1); 

接下來是poj的約瑟夫環問題:同樣,編號要改為從0開始,0-k-1為好人,k-n-1為壞人,報到m-1時退出。這裡我們直接用公式求數到的人的位置就好(注意這裡公式是m-1,和上面不同,這裡的m-1是計數,上面的m是根據公式推出來的,不要誤以為上面的m也是計數了),只要這個位置大於等於k,數到的就是壞人。求位置的公式s=(s+m-1)%(n-i),s,i都從0開始,n-i為剩下的人。

到這裡還沒完,如果簡單地列舉m是會超時的,這裡的思路是老師和我講的:假設我們進行到了只剩下兩個壞人時,即剩下的人表示為(g為好人,b為壞人,x為將要退出的人)gggg...bx或gggg...xb,第一種情況,m為t(k+1),(t=1,2..)時,最後乙個壞人會退出;第二種情況,m為t(k+1)+1,(t=1,2...)時,最後乙個壞人會退出。不論轉多少圈(t無論為多少),m都符合情況,都能清除最後乙個壞人。但題目要求最小的m,那麼,m就按k+1 + 1或k+1列舉即可。

我的**:

POJ 1012 約瑟夫問題

我是直接模擬的,因為實在想不到什麼好辦法,不過看到0 俗話說得好,不管黑貓白貓,抓到老鼠的就是好貓。於是在自家電腦模擬,打個表,就ac了。至於還有沒有其他方法,有待研究,大家有什麼好方法,請賜教,謝謝!1 模擬 方法是,m從2開始判斷,在1,2,3,2k中,每次找到第m個數,判斷如果是大於k的,那麼...

poj 1012 約瑟夫置換

一開始用的不是約瑟夫置換 關鍵是要儲存之前求出的值。因為只有13個數,所以也可以另開程式手動求出所有k值塞進陣列,這樣每次查詢都是o 1 0ms了 首先m值必須在 k 1 2kn,2k n 1 n 0,1,2 之間,然後 列舉。include include include include incl...

POJ 1012 約瑟夫問題

功能function description 約瑟夫環 列舉 poj 1012 開發環境environment dev c 4.9.9.1 技術特點technique 版本version 作者author 可笑痴狂 日期date 20120731 備註notes 大致題意 有k個壞人k個好人坐成一圈...