“約瑟夫問題”教學(xué)思路
說在前面
約瑟夫問題是一個經(jīng)典的數(shù)學(xué)應(yīng)用問題,它通過循環(huán)報數(shù)不斷刪除序列中的元素,直至剩下1個(或多個)人為止。編程解決約瑟夫問題的算法很多,基本思想都是模擬報數(shù)過程,區(qū)別在于數(shù)據(jù)結(jié)構(gòu)不同,刪除元素的方法也不一樣。
約瑟夫問題可以考查使用模運算實現(xiàn)循環(huán)報數(shù)功能,使用循環(huán)鏈表、循環(huán)隊列等數(shù)據(jù)結(jié)構(gòu)模擬報數(shù)和刪除元素過程,變例繁多、算法難度較高、綜合性強,是需要重點掌握的經(jīng)典案例。

教材文本



n=int(input("請輸入?yún)⑴c人數(shù)(N):"))
m=int(input("請輸入淘汰數(shù)(M):"))
a = [[i+1,i+1] for i in range(n-1)]
a.append(填空1) # 最后一個人的下一位是第一個人
pre = len(a) - 1 # 指向前驅(qū)節(jié)點
while 填空2: # 循環(huán)單鏈表中節(jié)點數(shù)量大于1
for i in range(1, m): # 報數(shù)[1,m-1]的人留下
pre = 填空3
a[pre][1] = 填空4 # 報數(shù)m的人離開(刪除a[pre][1])
print(f'幸存者位置為:{a[pre][0]}')
if i==m: # 報數(shù)為m時刪除k的后繼節(jié)點t
t=a[k][1] # 用t指向節(jié)點k的后繼節(jié)點
a[k][1]=a[t][1] # 修改k的后繼指針,以實現(xiàn)刪除節(jié)點t功能
if t==head: # 刪除頭節(jié)點時需要修改頭指針
head=a[k][1] # 或者head=a[t][1]
i=1 # 計數(shù)器歸1
long-=1 # 鏈表長度減1
程序通過修改k的后繼指針,實現(xiàn)刪除其后繼節(jié)點的功能。為了增強代碼的可讀性,程序設(shè)置變量t指向節(jié)點k的后繼節(jié)點,然后修改a[k][1]=a[t][1],這樣就能實現(xiàn)刪除節(jié)點t的功能了。為了使head始終指向鏈表的頭節(jié)點,當(dāng)被刪除節(jié)點是頭節(jié)點時需要修改頭指針head。
刪除某個節(jié)點后,程序讓計數(shù)器i歸1,并使記錄鏈表長度的變量long減1,準備下一輪報數(shù)。
n=int(input("請輸入?yún)⑴c人數(shù)(N):"))
m=int(input("請輸入淘汰數(shù)(M):"))
a = [[i+1,i+1] for i in range(n-1)]
a.append([n, 0]) # 最后一個人的下一位是第一個人
pre = len(a) - 1 # 指向前驅(qū)節(jié)點
while a[pre][1] != pre: # 循環(huán)單鏈表中節(jié)點數(shù)量大于1
for i in range(1, m): # 報數(shù)[1,m-1]的人留下
pre = a[pre][1]
a[pre][1] = a[a[pre][1]][1] # 報數(shù)m的人離開(刪除a[pre][1])
print(f'幸存者位置為:{a[pre][0]}')
教材程序通過遍歷鏈表來模擬報數(shù)過程,并刪除節(jié)點以實現(xiàn)淘汰人員功能,直至只剩一個節(jié)點為止。除此之外,你還能想到別的方法來解決約瑟夫問題嗎?例如使用一維數(shù)組和循環(huán)隊列等數(shù)據(jù)結(jié)構(gòu)來存儲數(shù)據(jù),又該如何編寫代碼呢?
需要本文word文檔、源代碼和課后思考答案的,可以加入“Python算法之旅”知識星球參與討論和下載文件,“Python算法之旅”知識星球匯集了數(shù)量眾多的同好,更多有趣的話題在這里討論,更多有用的資料在這里分享。
我們專注Python算法,感興趣就一起來!
相關(guān)優(yōu)秀文章:
