遞迴( recursion)是一種神奇的程式設計技巧,可以大幅簡化**,使之看起來更加簡潔。然而遞迴設計卻非常抽象,不容易掌握。通常,我們都是自上而下的思考問題, 遞迴則是自下而上的解決問題——這就是遞迴看起來不夠直觀的原因。
和遞迴相關的概念裡,線性遞迴/非線性遞迴、單向遞迴/非單向遞迴,是非常重要的,要想掌握遞迴技術,就必須要深入理解。關於遞迴的基本概念,有興趣的讀者,可以參考我的部落格《python 遞迴演算法指歸》。今天,僅就揹包問題qugpm談非單向遞迴函式如何返回全部結果。
揹包問題的背後,是世界七大數學難題之一,多項式複雜程度的非確定性問題。作為程式設計師,可以將該問題大致上理解為組合優化的問題。揹包問題通常被這樣描述:給定一組物品,每種物品都有自己的重量和**,在限定的總重量內,如何選擇,才能使得物品的總**最高。如果加上不同的限制和條件,揹包問題可以衍生出很多變種。比如,下面這道題看起來和揹包問題相去甚遠,實質上仍然是乙個典型的揹包問題。
在一款英雄對戰遊戲中,玩家擁有m件裝備和n位英雄,他可以給每一位英雄分配0件或多件裝備,而不同的英雄擁有不同數目的裝備時將獲得不同的攻擊力。玩家如何分配這m件裝備,可以使得n個英雄獲得的攻擊力的和最大?以玩家擁有5件裝備和3位英雄為例,下表共有3行6列,對應著3位英雄分別擁有從0到5件裝備時的攻擊力。
0件www.cppcns.com 1件
2件3件
4件5件
英雄1013
57
9英雄201
1337
英雄3045
67
即使不熟悉揹包問題,也不難找到解題思路:
找出將m件裝備分配給n位英雄的所有方案是解決問題的核心。這裡,迴圈巢狀是行不通的,因為巢狀層數是輸入變數。遞迴是我想到的可行的方法。
>>> def bag(m, n, series=list()):
if n == 1:
for i in range(m+1):
print(series+[i])
else:
for i in range(m+1):
bag(m-i, n-1, series+[i])
>>> bag(3,2) # 將3件裝備分配給2位英雄的全部方案
[0, 0]
[0, 1]
[0, 2]
[0, 3]
[1, 0]
[1, 1]
[1, 2]
[2, 0]
[2, 1]
[3, 0]
遞迴函式bag,列印出了將3件裝備分配給2位英雄的全部方案。顯然,這不是乙個單向遞迴,因為在同一級有多次遞迴呼叫,這意味著遞迴過程有多次從遞迴出口走出。對於非單向遞迴,是不能使用return返回結果的。那麼,如何讓遞迴函式返回全部方案呢?請看下面的例子。
>>> def bag(m, n, result, series=list()):
if n == 1:
for i in range(m+1):
result.append(series+[i])
#print(result[-1])
else:
for i in range(m+1):
bag(m-i, n-1, result, series+[i])
>>> result = list()
>>> bag(5, 3, result) # 將5件裝備分配給3位英雄,共有56種分配方案
>>> len(result)
56>>> result
[[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 0, 3], [0, 0, 4], [0, 0, 5],
[0, 1, 0], [0, 1, 1], [0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 2, 0],
[0, 2, 1], [0, 2, 2], [0, 2, 3], [0, 3, 0], [0, 3, 1], [0, 3, 2],
[0, 4, 0], [0, 4, 1], [0, 5, 0], [1, 0, 0], [1, 0, 1], [1, 0, 2],
[1, 0, 3], [1, 0, 4], [1, 1, 0], [1, 1, 1], [1, 1, 2], [1, 1, 3],
[1, 2, 0], [1, 2, 1], [1, 2, 2], [1, 3, 0], [1, 3, 1], [1, 4, 0],
[2, 0, 0], [2, 0, 1], [2, 0, 2], [2, 0, 3], [2, 1, 0], [2, 1, 1],
[2, 1, 2], [2, 2, 0], [2, 2, 1], [2, 3, 0], [3, 0, 0], [3, 0, 1],
[3, 0, 2], [3, 1, 0], [3, 1, 1], [3, 2, 0]程式設計客棧, [4, 0, 0], [4, 0, 1],
[4, 1, 0], [5, 0, 0]]
上面的**中,在呼叫遞迴函式之前,先建立乙個全域性的列表物件result,並作為引數傳遞給遞迴函式。遞迴呼叫結束後,全部的裝備分配方案就儲存在列表物件result中。
遍歷56種分配方案,計算每一種方案的攻擊力之和,儲存到乙個新的列表v中。p為3位英雄分別擁有從0到5件裝備時的攻擊力。
>>> p = [
[0,1,3,5,7,9],
[0,1,1,3,3,7],
[0,,4,5,6,7]
]>>> v = list()
>>> for item in result:
v.append(p[0][item[0]] + p[1][item[1]] + p[2][item[2]])
>>> v
[0, 3, 4, 5, 6, 7, 1, 4, 5, 6, 7, 1, 4, 5, 6, 3, 6, 7, 3,
6, 7, 1, 4, 5, 6, 7, 2, 5, 6, 7, 2, 5, 6, 4, 7, 4, 3, 6,
7, 8, 4, 7, 8, 4, 7, 6, 5, 8, 9, 6, 9, 6, 7, 10, 8, 9]
找出v列表最大值的序號,進而得到攻擊力最大的裝備分配方案。
>>> max(v)
10>>> result[v.index(max(v))]
[4, 0, 1]
最佳分配方案是第1位英雄持有4件裝備,第2位英雄沒有裝備,第3位英雄持有1件裝備,此時3位英雄的攻擊力之和為最大,其值為10。
遞迴非遞迴寫函式
2.編寫乙個函式實現n k,使用遞迴實現 分析 n的k次 n n n n n k個n 用遞迴的思想來講,就等於n n的 k 1 次方 include include pragma waring disable 4996 int fun int n,int k int main 3.寫乙個遞迴函式di...
python如何裝飾遞迴函式
裝飾函式printtime 列印遞迴函式執行時間 def printtime func wraps func def args,kwargs start time print func args,kwargs end time print spent time s end start 遞迴函式n d...
Akm函式遞迴與非遞迴解法
如下是akm函式的遞迴演算法,根據akm函式的遞迴定義就可以得出,請參考 int akmrecur int m,int n 非遞迴演算法沒有遞迴演算法簡單,你先計算一下akm 2,1 多計算幾遍 我建議2遍,並在計算的過程中,分析一下計算過程有什麼規律 如果你計算完了,就可以看下面的分析了 請不要懶...