貪心算法
貪心算法(又稱貪婪算法)是指,在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,他所做出的是在某種意義上的局部最優解。
貪心算法不是對所有問題都能得到整體最優解,關鍵是貪心策略的選擇,選擇的貪心策略必須具備無后效性,即某個狀態以前的過程不會影響以后的狀態,只與當前狀態有關。
貪心算法基本要素:
- 談心選擇:貪心選擇是指所求問題的整體最優解可以通過一系列局部最優的選擇,即貪心選擇來達到。這是貪心算法可行的第一個基本要素,也是貪心算法與動態規划算法的主要區別。貪心選擇是采用從頂向下、以迭代的方法做出相繼選擇,每做一次貪心選擇就將所求問題簡化為一個規模更小的子問題。對於一個具體問題,要確定它是否具有貪心選擇的性質,我們必須證明每一步所作的貪心選擇最終能得到問題的最優解。通常可以首先證明問題的一個整體最優解,是從貪心選擇開始的,而且作了貪心選擇后,原問題簡化為一個規模更小的類似子問題。然后,用數學歸納法證明,通過每一步貪心選擇,最終可得到問題的一個整體最優解。
- 最優子結構:當一個問題的最優解包含其子問題的最優解時,稱此問題具有最優子結構性質。運用貪心策略在每一次轉化時都取得了最優解。問題的最優子結構性質是該問題可用貪心算法或動態規划算法求解的關鍵特征。貪心算法的每一次操作都對結果產生直接影響,而動態規划則不是。貪心算法對每個子問題的解決方案都做出選擇,不能回退;動態規划則會根據以前的選擇結果對當前進行選擇,有回退功能。動態規划主要運用於二維或三維問題,而貪心一般是一維問題
貪心算法基本思路:
貪心算法的基本思路是從問題的某一個初始解出發一步一步地進行,根據某個優化測度,每一步都要確保能獲得局部最優解。每一步只考慮一個數據,他的選取應該滿足局部優化的條件。若下一個數據和部分最優解連在一起不再是可行解時,就不把該數據添加到部分解中,直到把所有數據枚舉完,或者不能再添加算法停止
例題一:
假設商店老板要找零n元錢,錢幣面額有:100元、50元、20元、5元、1元,如何找零使得所需錢幣的數量最少?

#假設商店老板需要找零n元錢,錢幣的面額有:100元、50元、20元、5元、1元,如何找零使得所需錢幣的數量最少? money = [100,50,20,5,1] def change_money(x): change = [0,0,0,0,0] for i,m in enumerate(money): change[i] = x // money[i] x = x % money[i] if x > 0: print("還剩%s" % x) return change print(change_money(356.2))
例題二:
一輛汽車加滿油后可行駛n公里,旅途中有k個加油站,加油站之間的距離存放在列表l中。汽車要怎么停靠加油才能使加油次數最少?

#一輛汽車加滿油后可行駛n公里。旅途中有k個加油站。設計一個有效算法,指出應在哪些加油站停靠加油,使沿途加油次數最少。 #對於給定的n(n <= 5000)和k(k <= 1000)個加油站位置,編程計算最少加油次數。 def greedy(n,k,l): num = 0 # 表示加油次數 for i in range(k): if l[i] > n: print('no solution') # 如果距離中得到任何一個數值大於n 則無法計算 return i, s = 0, 0 # 利用s進行迭代 while i <= k: s += l[i] if s >= n: # 當局部和大於n時則局部和更新為當前距離 s = l[i] # 貪心意在令每一次加滿油之后跑盡可能多的距離 num += 1 i += 1 print(num) if __name__ == '__main__': n = 100 k = 5 l = [50, 80, 39, 60, 40, 32] # 表示加油站之間的距離 greedy(n,k,l)
例題三:
有n個非負整數,將其按照字符串拼接的方式拼接為一個整數。如何拼接可以使得得到的整數最大?如何拼接可以使得得到的整數最小?
例:32,94,128,1286,6,71可以拼接出的最大整數為94716321286128,最小整數為12812863267194
動態規划