在《演算法圖解》裡面有一個蠻有意思的小案例,背景是一個廣播節目,要讓全美的50個周的聽眾都能夠聽到,但是每個電臺可能覆蓋多個州,每在一個電臺播出就需要一筆費用,所以就是從成本的角度來看,怎麼儘可能在所有的州都播出,這是一個典型的集合覆蓋的問題,而且在我們的生活中算是比較典型。
比如我們先縮小範圍,指定5個州,那麼50個州也是同樣的演算法。
states_need = set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]) # 傳入一個陣列, 它被轉換為集合
有的同學可能對這些州沒概念,這個簡稱就跟京代表北京,魯代表山東,甘代表甘肅一樣,細細一看,都是西部的一些州。
如何使用貪心演算法呢,就是選擇覆蓋儘可能多的州的電臺,然後逐步縮小範圍。那麼覆蓋面廣的州所對應的電臺就優先被選中,依次類推。
程式的實現是指定了一個集合states_need,裡面包含所有的州,每個電臺對應的州是透過初始化的陣列元素來實現的,按照一二三四五的順序來命名,當然實際上這種元素的排列set不是按照陣列名的順序,在這個場景裡是kfive,ktwo,kthree,kone,kfour
然後逐步縮小範圍來收斂,裡面比較特別的一點就是集合的運算,使用了 & ,得到的是交集,如果是並集是 |,差集是 -,
程式程式碼如下:
#!/usr/bin/env python# coding:utf-8states_need = set(["mt", "wa", "or", "id", "nv", "ut", "ca", "az"]) # 傳入一個陣列, 它被轉換為集合# 可供選擇的廣播臺清單stations = {}stations["kone"] = set(["id", "nv", "ut"])stations["ktwo"] = set(["wa", "id", "mt"])stations["kthree"] = set(["or", "nv", "ca"])stations["kfour"] = set(["nv", "ut"])stations["kfive"] = set(["ca", "az"])print(stations)# 最終選擇的廣播臺集合final_stations = set()while states_need:best_station = Nonestates_covered = set()for station, states_for_station in stations.items():covered = states_need & states_for_station # 求交集print("states_need:",states_need,"states_for_station:",states_for_station,"covered:",covered)if len(covered) > len(states_covered):best_station = stationstates_covered = coveredstates_need -= states_coveredfinal_stations.add(best_station)print("states_needed:",states_need,"best_station:",best_station,"final_stations:",final_stations)print("---")print("Final_stations:",final_stations)
為了方便除錯和得到一個迭代的結果,我加了幾處輸出日誌,工參考。
{'kfive': set(['ca', 'az']), 'ktwo': set(['mt', 'id', 'wa']), 'kthree': set(['ca', 'or', 'nv']), 'kone': set(['ut', 'id', 'nv']), 'kfour': set(['ut', 'nv'])}('states_need:', set(['wa', 'ut', 'ca', 'id', 'mt', 'az', 'or', 'nv']), 'states_for_station:', set(['ca', 'az']), 'covered:', set(['ca', 'az']))('states_needed:', set(['wa', 'ut', 'id', 'mt', 'or', 'nv']), 'best_station:', 'kfive', 'final_stations:', set(['kfive']))---('states_need:', set(['wa', 'ut', 'id', 'mt', 'or', 'nv']), 'states_for_station:', set(['mt', 'id', 'wa']), 'covered:', set(['mt', 'id', 'wa']))('states_needed:', set(['ut', 'or', 'nv']), 'best_station:', 'ktwo', 'final_stations:', set(['ktwo', 'kfive']))---('states_need:', set(['ut', 'or', 'nv']), 'states_for_station:', set(['ca', 'or', 'nv']), 'covered:', set(['or', 'nv']))('states_needed:', set(['ut', 'or', 'nv']), 'best_station:', 'ktwo', 'final_stations:', set(['ktwo', 'kfive']))---('states_need:', set(['ut', 'or', 'nv']), 'states_for_station:', set(['ut', 'id', 'nv']), 'covered:', set(['ut', 'nv']))('states_needed:', set(['ut', 'or', 'nv']), 'best_station:', 'ktwo', 'final_stations:', set(['ktwo', 'kfive']))---('states_need:', set(['ut', 'or', 'nv']), 'states_for_station:', set(['ut', 'nv']), 'covered:', set(['ut', 'nv']))('states_needed:', set(['ut', 'or', 'nv']), 'best_station:', 'ktwo', 'final_stations:', set(['ktwo', 'kfive']))---('states_need:', set(['ut', 'or', 'nv']), 'states_for_station:', set(['ca', 'az']), 'covered:', set([]))('states_needed:', set(['ut', 'or', 'nv']), 'best_station:', None, 'final_stations:', set(['ktwo', None, 'kfive']))---('states_need:', set(['ut', 'or', 'nv']), 'states_for_station:', set(['mt', 'id', 'wa']), 'covered:', set([]))('states_needed:', set(['ut', 'or', 'nv']), 'best_station:', None, 'final_stations:', set(['ktwo', None, 'kfive']))---('states_need:', set(['ut', 'or', 'nv']), 'states_for_station:', set(['ca', 'or', 'nv']), 'covered:', set(['or', 'nv']))('states_needed:', set(['ut']), 'best_station:', 'kthree', 'final_stations:', set(['ktwo', 'kthree', None, 'kfive']))---('states_need:', set(['ut']), 'states_for_station:', set(['ut', 'id', 'nv']), 'covered:', set(['ut']))('states_needed:', set(['ut']), 'best_station:', 'kthree', 'final_stations:', set(['ktwo', 'kthree', None, 'kfive']))---('states_need:', set(['ut']), 'states_for_station:', set(['ut', 'nv']), 'covered:', set(['ut']))('states_needed:', set(['ut']), 'best_station:', 'kthree', 'final_stations:', set(['ktwo', 'kthree', None, 'kfive']))---('states_need:', set(['ut']), 'states_for_station:', set(['ca', 'az']), 'covered:', set([]))('states_needed:', set(['ut']), 'best_station:', None, 'final_stations:', set(['ktwo', 'kthree', None, 'kfive']))---('states_need:', set(['ut']), 'states_for_station:', set(['mt', 'id', 'wa']), 'covered:', set([]))('states_needed:', set(['ut']), 'best_station:', None, 'final_stations:', set(['ktwo', 'kthree', None, 'kfive']))---('states_need:', set(['ut']), 'states_for_station:', set(['ca', 'or', 'nv']), 'covered:', set([]))('states_needed:', set(['ut']), 'best_station:', None, 'final_stations:', set(['ktwo', 'kthree', None, 'kfive']))---('states_need:', set(['ut']), 'states_for_station:', set(['ut', 'id', 'nv']), 'covered:', set(['ut']))('states_needed:', set([]), 'best_station:', 'kone', 'final_stations:', set(['ktwo', 'kthree', None, 'kfive', 'kone']))---('states_need:', set([]), 'states_for_station:', set(['ut', 'nv']), 'covered:', set([]))('states_needed:', set([]), 'best_station:', 'kone', 'final_stations:', set(['ktwo', 'kthree', None, 'kfive', 'kone']))---('Final_stations:', set(['ktwo', 'kthree', None, 'kfive', 'kone']))
最後的結果是:ktwo,kthree,kfive,kone這四個電臺。
當然貪心演算法得到的不是精確的結果,即可能不是最優解,算是一種近似演算法,能夠基本得到的最優解,而且效率很高。