北航算法作业一 约瑟夫环问题
一.單向鏈表模擬
class Node:def __init__(self, num, next):self.num = numself.next = nexta = [] # n個人 n = 3 # 數到k的人死去 k = 2 for i in range(0, n):a.append(Node(i, (i + 1) % n)) # 計數器 counter = 1 # 現在的人 now = a[0] while True:next = a[now.next]if next == now:#就剩下一個人了,游戲結束breakelse:counter += 1if counter == k:#計數器為k,要死人了counter = 0now.next = next.nextprint(str(next.num)+" has died",end='\n')else:#不死人,now=next,向后走一格now=next #打印唯一的幸存者 print(now.num)二.遞推公式法
f(n)=[f(n-1)+k]%n
編號從0開始,f(n)表示n個人數到k的死去最后的幸存者,顯而易見第一個死去的人是(k-1)%n,死者后面一人編號為0,再后面為1,以此類推,構成一個新的f(n-1).所以f(n)中的幸存者就是f(n)=[f(n-1)+k]%n.
#n個人 n=100 a=[0]*n #數到k的人死去 k=2 a[1]=0 for i in range(1,len(a)):a[i]=(a[i-1]+k)%i for i in range(1,len(a)):print(a[i],end=' ')輸出為
0 0 2 0 2 4 6 0 2 4 6 8 10 12 14 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70很顯然可以找到規律,數字周期為第0個周期長度為1,第1個周期長度為2,第2個周期長度為4,第三個周期長度為8....對于數字n,它所在的周期為log2(n),數字n在周期中的列數為n-2^log2(n).
當k=2時,f(n)=[n-2^log2(n)]*2
驗證上述結論:
from math import * for i in range(1,100):print((i-2**int(log2(i)))<<1)在上述表述中,一切計數都從0開始.從0開始,你會發現問題的表達形式會簡單很多,從0開始計數確實應該成為一種習慣.
三.k=2時的另一種遞推公式
f(2n)=2*f(n)
f(2n+1)=f(n)+1
下標一律從0開始,當有2n個人,數完一圈之后,奇數號人全跪了.給剩下的人重新編號,原來的0號還是0號,原來的2號變成1號,原來4號變成2號....即原來的2n號變成了現在的n號.剩下n個人的幸存者為第f(n)號,這個人對應原來的f(n)*2號.所以f(2n)=2f(n).
當有2n+1個人,數完一圈之后,奇數號人全跪了,最后一個人2n號沒有跪,下一個跪的是0號.這樣第一圈算跪了n+1個人.對剩下的n個人重新編號,原來的2號變成0號,原來的4號變成1號,原來的6號變成2號,原來的8號變成3號....即原來的2n號變成了現在的n-1號.剩下n個人的幸存者為f(n)號,對應原來的(f(n)+1)*2號,所以f(2n+1)=2f(n)+2.
對于這種問題,關鍵在于重新編號.
四.比較快的遞推公式法
遞推公式f(n)=(f(n-1)+k)%n,復雜度為O(n).有一個更快的遞推式:
f(n)=[f(n-n/k)+n-n%k+f(n-n/k)/(k-1)]%n
f(n-n/k)第一輪輸完之后,n/k個人死了,就剩下n-n/k個人.剩下的任務就是找到f(n-n/k)這個人對應f(n)中的哪個人.f(n-n/k)每(k-1)個人中可以插入一個死者,這些死者是要算數的.最后一個死者是n-n%k,他的下一個為0號,這是偏移量.這個遞推公式復雜度
f(n)=常數*f(n-n/k)
復雜度為log(n)級別.
五.關于約瑟夫環
約瑟夫環花樣繁多,比如給定一個數組
1 4 當第一個人死去,下一個死去的人是第一個人左邊的第4個人
2 3 當2號人死去,下一個死去的人是第二個人左邊第3個人
3 4 當3號人死去,下一個死的人是他左邊的第4個人
...
給定一個數組,問最后的幸存者是誰.
這個問題可以用線段樹來求解.
總結
以上是生活随笔為你收集整理的北航算法作业一 约瑟夫环问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html文本超出自动换行、显示省略号
- 下一篇: SpringMVC处理自定义异常,通过读