1. 程式人生 > >約瑟夫 (Joseph) -- ACM PKU 1012 解題報告

約瑟夫 (Joseph) -- ACM PKU 1012 解題報告

問題描述:The Joseph's problem is notoriously known. For those who are not familiar with the original problem: from among n people, numbered 1, 2, . . ., n, standing in circle every mth is going to be executed and only the life of the last remaining person will be saved. Joseph was smart enough to choose the position of the last remaining person, thus saving his life to give us the message about the incident. For example when n = 6 and m = 5 then the people will be executed in the order 5, 4, 6, 2, 3 and 1 will be saved.
Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys will be executed before the first good guy.

參見 http://acm.pku.edu.cn/JudgeOnline/problem?id=1012

我的總體思路是,對從每個 m=k+1, k+2, ... ,計算出前 k 個被殺的人,如果他們的編號都比 k 大,則表示所有所有壞人都被殺掉了,從而找到了最小的 m。

用 rest 表示還有多個人活著,初值為 2k。當 start 表示當前輪從哪個編號開始計算,初值為 1。用 killed 表示當前輪要被殺的人的編號。則 killed = (start - 1+ m) mod rest。這時,對 killed 後面的人進行重新編號:killed+1 -> killed,killed+2 -> killed+1,..., rest -> rest -1。即被執行的那個人的後面所有的編號都遞減 1。在新的編號下,新的開始計算編號為 start = killed。以此反覆直到某一輪中, killed <= 4 或只剩下 k 個人。如果是後者,則 m 為解。這個演算法的關鍵在於,在新的編號下,好人的編號都是不變的。而壞人的編號可能一直在變化,而正是我們不關心壞人的編號變化情況,才使得這演算法成立。在真正的實現中,並不需要真的去把被殺者的後面的人的編號都遞減 1,原因就我剛才說的,我們不必關心壞人的編號變化。

此題是經典 Joseph 的一個變體。最原始的題目正是題目描述的第一部分,即求最後的倖存者,可以用動態規劃求解。

假設第一個被殺的人為 k = m mod n。接著,我們對所有人都進行重新編號:k+1 mod n -> 1, k+2 mod n -> 2,k+x mod n -> x,...,k-1 mod n -> n-1。則問題變了只剩下 n-1 個人的情況。假設在這個新的編號下的 n-1 人中,最後倖存的是 x,則從上面的對映可知,其原來的編號為 (x + k) mod n。記 f(n) 為在 n 個人的 Joseph 問題中倖存者的編號,則 f(n) = (f(n-1)+m) mod n。而 f(1) = 1。當 m=2 時,f(n) 有解析解,詳見 http://en.wikipedia.org/wiki/Josephus_problem。