貪婪算法

1、概念

貪婪算法: 每步都採取最優的做法。
優點: 簡單易行。
特點: 得到的結果是最優解或者與最優解相當接近。所以也不是任何情況下行之有效的。可以看成是一個近似算法。

2、教室課表調度問題

課程表如下,如何選出儘可能多且時間不衝突的課程呢?

英語 8 :00 AM 9:00 AM
思修 8:30 AM 9:30 AM
C語言 9:00 AM 10:00 AM
計算機概論 9:40 AM 10:40 AM
Python 10:20 AM 11:20 AM

貪婪算法做法具體如下:

  1. 選出最早結束的課,就是要在這間教室上的第一堂課。
  2. 接下來,必須選擇第一堂課後纔開始的課。同樣,選擇最早結束的課,這將是要在這間教室上的第二堂課。以此類推。

最終貪婪算法求出這間教室課表安排順序爲: 英語、C語言、Python。

3、揹包問題

舉例揹包問題主要討論貪婪算法並非是在任何情況下行之有效的。

假設你是一個小偷,你揹着可裝35磅重東西的揹包,在商場伺機盜竊各種可裝入揹包的商品。商場的商品重量和價格如下:

商品名 價格 重量
音響 6000美元 30磅
筆記本電腦 4000美元 20磅
吉他 3000美元 15磅

採用貪婪策略,具體做法如下:

  1. 盜竊可裝入揹包的最貴商品。
  2. 再盜竊還可裝入揹包的最貴商品,以此類推。

採用貪婪策略求出只偷到了6000美元的東西,但是如果不偷音響,而是偷筆記本和吉他,那將偷到7000美元的東西。

啓示:

在某些情況下,完美是優秀的敵人。有時候,你只需要找到一個能夠大致解決問題的算法,此時貪婪算法正好可派上用場,因爲他們實現起來很容易,得到的結果又與正確結果相當接近。

4、集合覆蓋問題

假設你辦了一個廣播節目,要讓全國的聽衆都能收聽得到,爲此你需要決定在哪些廣播臺播出,在每個廣播臺都需要支付費用,因此你力圖在儘可能少的廣播臺播出,然而每個廣播臺都覆蓋特定的區域,不同廣播臺的覆蓋區域可能重疊。如何找出覆蓋全國34個省級區域的最小廣播臺集合呢?看起來很簡單,但實現起來非常難。具體方法如下:

  1. 列出每個可能的廣播臺集合,這個被稱爲冪集,可能的子集爲 2n2^n 個。
  2. 在這些集合中,選出覆蓋全中國34個省級區域的最小集合。

此時問題來了,這時算法的運行時間爲 O(2n)O(2^n) ,如果廣播臺很多,沒有任何算法能足夠快地解決這個問題。怎麼辦呢?
貪婪算法可以化解危機,使用貪婪算法可以得到非常接近的解。
使用貪婪算法步驟如下:

  1. 選出這樣一個廣播臺,即它覆蓋了最多未覆蓋州。即便這個廣播臺覆蓋了一些已覆蓋的省級區域,也沒有關係。
  2. 重複第一步,直到覆蓋了所有的省級區域。

這個算法的運行時間爲 O(n2)O(n^2),其中n爲廣播臺數量。

代碼(Python3):
  1. 出於簡化考慮,假設省級區域只有江西省、廣東省、湖北省、福建省、廣西省、雲南省、四川省、山東省。可以創建一個列表,其中包含要覆蓋的省級區域。

    states_needed = set(['江西省','廣東省','湖北省','福建省','廣西省','雲南省','四川省','山東省']) #傳入一個列表,將其轉換爲集合
    
  2. 廣播臺清單,使用散列表來表示。

    stations = {}
    stations['頻道1'] = set(['江西省','廣東省','福建省'])
    stations['頻道2'] = set(['四川省','山東省','廣西省'])
    stations['頻道3'] = set(['山東省','湖北省','福建省'])
    stations['頻道4'] = set(['雲南省','湖北省','江西省'])
    
  3. 最後使用一個集合來存儲最終選擇的廣播臺。

    final_stations = set()
    
  4. 開始計算,遍歷所有的廣播臺,從中選擇覆蓋了最多的未覆蓋的廣播臺。將這個廣播臺存儲在best_station中。把該廣播臺覆蓋的所有未覆蓋的省級區域放入states_covered集合。for循環每個廣播臺,並確定它是否是最佳的廣播臺。for循環結束後將best_station添加到最終的廣播臺列表中。

    best_station = None
    states_covered = set()
    for station,states_for_station in stations.items():
    	covered = states_needed & states_for_station #取交集
    	if len(covered) > len(states_covered):
    		best_station = station
    		states_covered = covered
    final_station.add(best_station)
    
  5. 由於覆蓋了一些省級區域,因此不需要覆蓋這些省級區域,還需更新states_needed。

    states_needed -= states_covered 
    
  6. 不斷循環,直到states_needed 爲空,這個循環完整代碼:

    while states_needed:
    	best_station = None
    	states_covered = set()
    	for station,states_for_station in stations.items():
    		covered = states_needed & states_for_station #取交集
    		if len(covered) > len(states_covered):
    			best_station = station
    			states_covered = covered
    	states_needed -= states_covered 
    	final_stations.add(best_station)		
    
  7. 最後打印final_stations,輸出:
    在這裏插入圖片描述

5、NP完全問題

NP完全問題: 多項式複雜程度的非確定性問題,簡單的理解就是 “難解”,需要計算所有的解,並從中選出最小/最短的那個。所以對於NP完全問題,一般採用近似求解,採用算法如:貪婪算法

判斷是否爲NP完全問題:

  1. 元素較少時算法運行的速度非常快,但隨着元素數量的增加,速度會變得非常慢,這時可能是NP完全問題。
  2. 涉及”所有組合“的問題通常是NP問題。
  3. 不能將問題分成小問題,必須考慮各種可能的情況。這個可能是NP完全問題。
  4. 如果問題涉及序列(旅行商問題中的城市序列)且難以解決,它可能就是NP完全問題。
  5. 如果問題涉及集合(如廣播集合)且難以解決,它可能就是NP完全問題。
  6. 如果問題可轉換未集合覆蓋或旅行商問題,那它肯定是NP完全問題。

6、總結

  • 貪婪算法尋找局部最優解,企圖以這種方式獲取全局最優解。
  • 對於NP完全問題,還沒有找到快速解決的方案。
  • 面臨NP完全問題,最佳的做法是使用近似算法。
  • 貪婪算法易於實現、運行速度快,是不錯的近似算法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章