與動態規劃類似,貪心演算法也將問題化簡為規模較小的子問題,並通過遞迴解決子問題來獲取整個問題的解。不同的是,貪心問題不對子問題進行比較,而是只生成乙個非空的子問題,而使選擇在當時看上去是最優的(即「貪心」的含義)。
幾個互相競爭的活動都要求以獨佔的方式占用某個公用資源(如選修課程對個人可支配時間的要求,或會議對會議室的要求),每個活動都有開始時間和結束時間。如何安排活動,使在總時間內開展的活動次數最多?形式化的,一組活動組成的集合 $s=$ ,每乙個活動 $a_i$ 都有開始時間 $s_i$ 和結束時間 $f_i$ 。求一組互相相容的活動的最大子集合 $s'$。
貪心演算法:
將所有活動按照結束時間排序,得到新的 $s$,首先選取結束時間最小 $a_1$ 的加入解 $s'$,然後檢查 $a_2$ ,如果 $a_2$ 的開始時間大於當前已加入解的所有活動(目前就乙個 $a_1$)的結束時間,那麼就捨棄之,否則將其加入解 $s'$ ,再檢查 $a_3$,以此類推。
能夠證明,貪心演算法獲取的是全域性最優解:
我們可以說,在排序後的 $s$,第乙個活動 $a_1$(結束時間最早的活動)一定在最優解 $s'$ 中。為什麼呢?因為假設 $s'$ 不包含 $a_1$,那麼一定包含乙個與 $a_1$ 不相容的 $a_i$ ,是吧?(如果這都不能滿足,直接向 $s'$ 中加入 $a_1$ ,得到的新子集就比 $s'$ 多了乙個元素,那麼 $s'$ 就不是最優解了)然後,我們可以斷言,從 $s'$ 去掉 $a_i$ 再加上 $a_1$,$s'$ 仍然是最優解。
為什麼呢?因為 $a_1$ 的結束時間是最早的,所以 $a_i$ 與 $a_1$ 不相容的方式只能是:$a_i$ 的開始時間比 $a_1$ 結束時間早(但結束時間比 $a_1$ 結束時間晚),而且因為 $s'$ 中除了 $a_i$ 的其他活動都與 $a_i$ 相容(理所當然,否則 $s'$ 連解都不是,何談最優解?),這些其他活動都會出現在 $a_i$ 後面(也就是這些活動的開始時間比 $a_i$ 的結束時間晚),而不是前面。如果出現在前面呢? 拜託,如果這些活動在 $a_i$ 前面,那麼這些活動的結束時間比 $a_i$ 的開始時間早,也就是比 $a_1$ 的結束時間早。這怎麼可能呢?$a_1$ 就是$s$ 中具有最早結束時間的活動了啊。
原理說起來拗口,實現做起來卻相當簡單:
classactvty
const
double getstart() const
const
double getend() const
const
int getid() const
bool
operator
<(const actvty& tmp) const
private
:
double
_start;
double
_end;
int_id;
};std::vector
slctn(std::vector&all)
}return
rslt;
}
練習16.1-3 假設用多個資源對一組活動進行排程,我們希望使用盡可能少的資源來滿足所有活動要求。
思路:和活動選擇問題類似,只不過當乙個活動不能被(當前開闢的資源)滿足時,我們不是將它捨棄,而是新開闢乙個資源供其使用。
竊賊在偷竊一家商店時發現有 $n$ 件物品 $s=a_1,a_2...a_n$ ,每一件物品 $a_i$ 都有其價值 $v_i$ 和重量 $w_i$ ,作為乙個有尊嚴的竊賊,他曾發誓每次只偷最多 $w$ 重量的貨物,那麼如何在不違背誓言的情況下,從贓物中獲得最大的價值?
貪心演算法:
將所有物品按照 $v_i/w_i$ 值(姑且稱為「單價」吧)排序,然後先拿單價最高的,然後拿單價次高的,如果拿到乙個物品後超重了,那就捨棄它並繼續上述過程,直到商店裡所有剩下物品中的任意一件都會使盜賊的贓物超重。
0-1揹包問題是np的,所以貪心演算法不保證最優解。乙個簡單的例子就是:竊賊只偷取 10kg 物體,商店裡只有兩件物品,一件1kg,價值20元,單價20,另一件9.5kg,價值950元,單價10元。如果竊賊遵循貪心演算法,就不能獲得最優解了。
習題16.2-4某教授駕車從 a 地到 b 地,總里程數確定。油箱中的汽油能支援的里程也是確定的,途中有若干個加油站。教授希望加油的次數盡量少,請確定需要加油的加油站,支援教授的車駛完全程。(假設教授出發時郵箱是滿的)。
這個演算法可以證明是最優的,即假設加油站序列為 $s=$,貪心解中的第乙個加油站為 $s_i$ 一定在最優解中。如果 $s_i$ 不在最優解中,那麼最優解中一定有乙個加油站 $s_p$ 在 $s_i$ 之前,否則車開不到 $s_i+1$ 。假設最優解中的第二個加油站為 $s_q$ ,那麼從最優解中去掉 $s_p$ 加上 $s_q$ 仍然是最優解。
習題16.2-7兩個集合 $a$ 和 $b$ ,各有 $n$ 個正整數,你可以按照自己的意願對其進行排序。重新排序後,設 $a_i$ 為 $a$ 中的第 $i$ 個元素,$b_i$ 為 $b$ 中的第 $i$ 個元素。請排序元素,使 $\prod a_^}$ 最大。
思路:全部遞增排序就是。證明也很簡單,就是證明當 $a_1>b_1$ 且 $a_2>b_2$ 時(當然都是正整數啊),$a_1^>a_2^$ 。
演算法導論之貪心演算法
參考 下面請看示例題 有n個商品,每個商品的重量為wi,為 pi,現有乙個揹包,最多能裝 的重量 其中 0 i問 怎樣裝能使包中裝入的商品價值最高 對於每個商品可以只裝該商品的一部分 偽 引數分別為 n 物品數 m 揹包最多能裝的重量 v 價值陣列 w重量陣列 void knapsack int n...
貪心演算法 1 演算法導論 21
我們先來看看乙個適應貪心演算法求解的問題 選擇活動問題。假定有乙個 n 個活動的集合 s 每個活動 a i 的舉辦時間為 s i,f i 0 leqslant s i f i 並且假定集合 s 中的活動都已按結束時間遞增的順序排列好。由於某些原因,這些活動在同一時刻只能有乙個被舉辦,即對於任意兩個活...
演算法導論05 貪心演算法 Dijkstra演算法
問題描述 請設計乙個演算法,實現在乙個有向圖中,給出乙個源點,計算該源點到其他所有頂點的單源最短路徑。演算法描述 dijkstra演算法的目的是尋找單源最短路徑,其具有以下最優子結構性質 最短路徑上的子路徑也是兩個頂點的最短路徑,此性質可以用cut paste反證 見筆記 因此,該演算法滿足貪心演算...