數學分析
經典演算法–約瑟夫環問題的三種解法
問題描述:n個人圍成一圈,從第乙個人開始從1開始報數,報到m的人出圈,剩下的人繼續從1開始報數,報到m的人出圈;如此往復,直到所有人出圈。(模擬此過程,輸出出圈的人的序號)
迴圈的開始和結束:迴圈的結束取決於圈內是否還有「人」,可以用乙個變數alive表示初始人數,每一次出圈,alive - 1。判斷alive是否非0即可。
while(alive > 0)
每一次迴圈,就是「過」乙個人,但是,這個人有兩種不同的狀態:在圈內和不在圈內;在圈內就報數,number+1,不在圈內就不參與報數,number不變。
假設有n個int元素的陣列,每乙個int元素表示乙個「人」;並且,取值為0和1, 1表示在圈內,0表示不在圈內,所以,如果這個人在圈內,number + 1;如果這個人不在圈內,number + 0。那麼,在報數的時候,不需要考慮這個人在不在圈內(每乙個人都需要加1或加0,所以,可以在這塊優化一下程式)。
void
joseph
(int count,
int doom)
//與總人數count取餘,則可以使index在0~count-1之間 一直迴圈,達到迴圈陣列的目的
index =
(index +1)
% count;
}printf
("\n");
free
(circle)
;//結束後一定要釋放circle所申請的空間
}
初始情況
一共n個人(編號0,1,2… n-1),組成乙個環。第乙個人從1開始報數,報數到m的人出環,然後,下乙個人重新開始從1開始報數,直到環中只有乙個人。
分析:第乙個出環的人編號是 (m-1)%n,設之為(k-1)
剩下的n-1個人組成了乙個新的約瑟夫環(以編號為k==m%n的人開始):
k k+1 k+2 … n-2, n-1, 0, 1, 2, …,k-3, k-2
現在我們把他們的編號做一下轉換:
x』 -> x
k --> 0
k+1 --> 1
k+2 --> 2……
k-2 --> n-2
k-1 --> n-1
變換後就完完全全成為了(n-1)個人報數的子問題,假如我們知道這個子問題的解:例如x是最終的勝利者,那麼根據上面這個表把這個x變回去不剛好就是n個人情況的解嗎!
x ->x'?(這正是從n-1時的結果反過來推n個人時的編號!)
0 -> k
1 -> k+1
2 -> k+2……
n-2 -> k-2
變回去的公式 x』=(x+k)%n
那麼,如何知道(n-1)個人報數的問題的解?只要知道(n-2)個人的解就行了。(n-2)個人的解呢?只要知道(n-3)的情況就可以了 ---- 這顯然就是乙個遞迴問題:
令f[i]表示i個人玩遊戲報m退出最後勝利者的編號,最後的結果就是f[n]
遞推公式
f[1]=0;
f[i]=(f[i-1]+k)%i = (f[i-1] +m%i) % i = (f[i-1] + m) % i ; (i>1)
1.遞迴:
#include
intjosephus
(int n,
int m)
else
}int
main()
scanf
("%d"
,&m)
;int result =
josephus
(n, m)
;printf
("%d\n"
, result+1)
;}return0;
}
2.迭代:
#include
intmain()
scanf
("%d"
,&m)
; result =0;
for(i =
2; i <= n; i++
)printf
("%d\n"
, result +1)
;}return0;
}
約瑟夫問題 約瑟夫環
約瑟夫 問題 有時也稱為約瑟夫斯置換,是乙個出現在電腦科學和數學中的問題。在計算機程式設計的演算法中,類似問題又稱為約瑟夫環。又稱 丟手絹問題 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死...
約瑟夫問題 約瑟夫環
約瑟夫問題 有時也稱為約瑟夫斯置換,是乙個出現在電腦科學和數學中的問題。在計算機程式設計的演算法中,類似問題又稱為約瑟夫環。又稱 丟手絹問題 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也...
約瑟夫環問題
約瑟夫環問題 問題描述 編號是1,2,n的n個人按照順時針方向圍坐一圈,每個人持有乙個密碼 正整數 一開始任選乙個正整數作為報數上限值m,從第乙個人開始順時針方向自1開始順序報數,報到m時停止報數。報m的人出列,將他的密碼作為新的m值,從他在順時針方向的下乙個人開始重新從1報數,如此下去,直到所有人...