程式設計之美1 3 一摞烙餅的排序(Python)

2021-12-29 20:14:29 字數 3182 閱讀 5846

問題:

星期五的晚上,一幫同事在希格瑪大廈附近的「硬碟酒吧」多喝了幾杯。程式設計師多喝了幾杯之後談什麼呢?自然是演算法問題。有個同事說:「我以前在餐館打工,顧客經常點非常多的烙餅。店裡的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好——小的在上面,大的在下面。由於我乙隻手托著盤子,只好用另乙隻手,一次抓住最上面的幾塊餅,把它們上下顛倒個個兒,反覆幾次之後,這摞烙餅就排好序了。我後來想,這實際上是個有趣的排序問題:假設有n塊大小不一的烙餅,那最少要翻幾次,才能達到最後大小有序的結果呢?」

你能否寫出乙個程式,對於n塊大小不一的烙餅,輸出最優化的翻餅過程呢?

分析: 題目要求的是最優化方案,而不是僅僅將其排好序。一種簡單的排序方法是,首先將最上面到最大的餅翻轉,這樣最大的餅到了最上面,再整體翻轉,這樣最大的餅就排好序了。按照這樣的方法依次去拍n-1大的,n-2大的……經過2n-2次翻轉,完成排序。也就是說,這個問題的最優解的乙個上界是2n-2,我們要尋找最優化的解。

尋找最優解的很直接的想法就是搜尋。搜尋的缺點是相對其他方法比較消耗記憶體和時間,但是比較通用,很多問題也只適合用搜尋解,其他方法不適合用。動態規劃相比搜尋會有更好的效率。考慮如果使用動態規劃,動態規劃需要劃分問題具有優化子結構,以及子問題重疊性。但在這個問題裡似乎不太好劃分子問題。

搜尋的步驟就是把全部的交換方式組織成一棵樹,對這顆樹進行遍歷操作,到達葉子節點表示找到了一種可行解,我們要尋找的是所有可行解中的最優情況。廣度優先遍歷需要儲存整個樹在記憶體中,非常消耗空間,因此使用深度優先遍歷。對深搜的優化可以使用分支定界,對不可能的解空間減少不必要的搜尋。樹的建立的過程就是遍歷的過程,由於需要進行回退,因此不能在原陣列上進行排序,而是需要額外的空間進行儲存,因此考慮在每個節點儲存當前整個陣列。樹的建立是動態的,一旦確定是需要拋棄的,就直接刪除節省空間。

總結一下:

1. 設有n張餅,交換方式上界為2n-2,那麼每個節點有n-1個子節點

2. 實際上每個節點有n-2個子節點,因為有乙個節點必然不成立:不可能和上一層的交換方式相同,那樣就換回去了

3. 但是這個節點的位置還得留著,給個空指標即可

4. 每個節點儲存的內容有:當前陣列,層數,全部的交換步驟

5. 根節點層數標為0,因為我們要的實際上是交換次數

6. 需要乙個全域性變數,儲存當前已經找到的可行解的上界

遍歷和剪枝的過程:

1. 對於每個節點,考察它是否已經排好序

2. 如果已經排好序,比較它和當前的上界的大小,如果更小,那麼修改上界為當前值。返回

3. 如果沒有排好序,考察它是否已經達到上界

4. 如果已經達到上界,返回

5. 如果沒有到達上界,建立它的子節點

這樣看下來發現其實不需要儲存這棵樹,只需要乙個棧就行了。每個節點儲存著之前的交換資訊。差不多可以開始寫**了。jetbrains的pycharm社群版不久之前宣布開源,正好試用一下。python中的list可以作為棧使用,棧頂為list的末尾,棧底為起始位置,這個要記清楚。注意我們假設每一張餅大小都不相同。

寫完了,感覺pycharm相當不錯啊,除錯比pydev強多了。上python**

#!/usr/bin/python

__author__ = 'dell'

class node:

cakes =

currentlevel = 0

steps =

def inputcakes(cakes):

global n

global upperbound

n = int(raw_input('n:'))

upperbound = 2 * n - 2

for i in range(0, n):

cakes.append(int(raw_input(str(i) + ':')))

def init():

global stack

node = node()

inputcakes(node.cakes)

#node.cakes = swap(node.cakes, 1)

stack.append(node)

def swap(cakes, position):

newcakes = cakes[:]

for i in range(0, position / 2 + 1):

temp = newcakes[i]

newcakes[i] = newcakes[position - i]

newcakes[position - i] = temp

return newcakes

def issorted(cakes):

for i in range(0, len(cakes) - 1):

if cakes[i] > cakes[i+1]:

return false

return true

def dfs():

global stack

global upperbound

global n

while len(stack) != 0:

node = stack[-1]

stack.pop()

if issorted(node.cakes):

print 'found:', node.steps

if node.currentlevel < upperbound:

upperbound = node.currentlevel

else:

if node.currentlevel < upperbound:

for i in range(1, n):

if len(node.steps) == 0 or (len(node.steps) > 0 and i != node.steps[-1]):

childnode = node()

childnode.cakes = swap(node.cakes, i)

childnode.currentlevel = node.currentlevel + 1

childnode.steps = node.steps[:]

childnode.steps.append(i)

stack.append(childnode)

n = 0

upperbound = 0

stack =

if __name__ == '__main__':

init()

dfs()

程式設計之美1 3 一摞烙餅的排序

程式設計之美 讀書筆記 1.3 一摞烙餅的排序 問題 星期五的晚上,一幫同事在希格瑪大廈附近的 硬碟酒吧 多喝了幾杯。程式設計師多喝了幾杯之後談什麼呢?自然是演算法問題。有個同事說 我以前在餐館打工,顧客經常點非常多的烙餅。店裡的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好 小的在上...

程式設計之美 一摞烙餅排序

問題 星期五的晚上,一幫同事在希格瑪大廈附近的 硬碟酒吧 多喝了幾杯。程式設計師多喝了幾杯之後談什麼呢?自然是演算法問題。有個同事說 我以前在餐館打工,顧客經常點非常多的烙餅。店裡的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好 小的在上面,大的在下面。由於我乙隻手托著盤子,只好用另乙...

程式設計之美 一摞烙餅的排序

問題描述 星期五的晚上,一幫同事在希格瑪大廈附近的 硬碟酒吧 多喝了幾杯。程式設計師多喝了幾杯之後談什麼呢?自然是演算法問題。有個同事說 我以前在餐館打工,顧客經常點非常多的烙餅。店裡的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好 小的在上面,大的在下面。由於我乙隻手托著盤子,只好用...