算法——貪心

Aha,又是新的一天,今天我們思考一下心算法。

作爲佛教三毒之首的貪竟然也堂而皇之成爲一種算法,供後人瞻仰禮拜。阿彌陀佛,罪過,罪過。之前的我是一直將這些東西視爲封建教條一樣束縛人的東西,慢慢的,從納斯姐身上我開始理解原本存在於電影臺詞中的話語“人生就是一場修行”,這些妄念是需要在修行中克服掉的。

我呸,廢話!

概念

貪心算法在對問題求解是,總是做出在當前看來最好的選擇,也就是說不從全局考慮,而是從局部考慮,做出局部最優選擇

貪心算法不是對所有問題都能得到整體最優解,關鍵是貪心策略的選擇,選擇的貪心策略必須具備無後效性,即某個狀態以前的過程不會影響以後的狀態,只與當前狀態有關。

採用逐步構造最優的方法,在每個階段都做出看上去最好的決策。

基本要素

貪心選擇:整體最優解可以通過一系列局部最優的選擇來達到,這是貪心與動態規劃的主要區別。貪心選擇是採用自頂向下、以迭代的方法做出相繼選擇,每做一次貪心選擇就將所求問題簡化爲一個規模更小的子問題。

對於一個具體問題,要確定它是否具有貪心選擇的性質,我們必須證明每一步所作的貪心選擇最終能得到問題的最優解。通常可以首先證明問題的一個整體最優解,是從貪心選擇開始的,而且作了貪心選擇後,原問題簡化爲一個規模更小的類似子問題。然後,用數學歸納法證明,通過每一步貪心選擇,最終可得到問題的一個整體最優解。

最優子結構:問題的最優解包含其子問題的最優解

與動態規劃的差異

相同點:都具有最優子結構性質

不同點:動態規劃每一步的解依賴子問題的解,而貪心算法不依賴子問題的解,只與當前狀態有關。

貪心算法中作出的每步貪心決策都無法改變,因爲貪心策略是由上一步的最優解推導下一步的最優解,而上一部之前的最優解則不作保留,貪心算法每一步的最優解一定包含上一步的最優解。動態規劃算法中全局最優解中一定包含某個局部最優解,但不一定包含前一個局部最優解,因此需要記錄之前的所有最優解。

貪心:自頂向下    動態規劃:自底向上

基本思路

貪心算法的基本思路是從問題的某一個初始解出發一步一步地進行,根據某個優化測度,每一步都要確保能獲得局部最優解。每一步只考慮一個數據,他的選取應該滿足局部優化的條件。若下一個數據和部分最優解連在一起不再是可行解時,就不把該數據添加到部分解中,直到把所有數據枚舉完,或者不能再添加算法停止。

(百度百科)

參考:https://blog.csdn.net/liufeng_king/article/details/8709005

例子

活動安排問題

問題描述:

設有n個活動的集合E={1,2,…,n},其中每個活動都要求使用同一資源,而在同一時間內只有一個活動能使用這一資源。
每個活動i都有一個要求使用該資源的起始時間si和一個結束時間fi,且si<fi。如果選擇了活動i,則它在半開時間區間[si ,fi )內佔用資源。若區間[si ,fi )與區間[sj,fj )不相交,則稱活動i與活動j是相容的。當 si ≥ fj 或 sj ≥ fi 時,活動i與活動j相容。
活動安排問題就是在所給的活動集合中選出最大的相容活動子集合

分析:是否滿足貪心算法的基本要素:首先要確實貪心準則,然後看是否滿足兩個要素:最優子結構、貪心選擇。

貪心準則:在未安排的活動中選擇結束時間最早的進行安排。需要首先對活動進行排序

代碼實現:

Public static void greedySelector(int s[] , int f[],  bool a [])
{     int n=s.length-1;
       a[0]=true;
       int j=0;   int count=1;
       for (int i=1;i<=n;i++) {
            if (s[i]>=f[j]) { a[i]=true; j=i; count++; }
            else a[i]=false;
       }
    return count;
}

非0-1揹包問題

問題描述:與動態規劃中的揹包問題不同,這裏的物品不是0-1的問題,也就是說,物品像麪包一樣可以切分成塊。

分析:按照單位質量價值從大到小進行排序,進行貪心。算法的複雜度在於排序問題。

 

單源最短路徑(Dijkstra算法解法)

問題描述:給定帶權有向圖G =(V,E),其中每條邊的權是非負實數。另外,還給定V中的一個頂點,稱爲源。現在要計算從源到所有其它各頂點的最短路徑長度。這裏路徑的長度是指路徑上各邊權之和。

參考:https://blog.csdn.net/qq_35644234/article/details/60870719https://blog.csdn.net/qq_39521554/article/details/79333690

分析:Dijkstra算法採用的是一種貪心的策略,聲明一個數組dis來保存源點到各個頂點的最短距離和一個保存已經找到了最短路徑的頂點的集合:T,初始時,原點 s 的路徑權重被賦爲 0 (dis[s] = 0)。若對於頂點 s 存在能直接到達的邊(s,m),則把dis[m]設爲w(s, m),同時把所有其他(s不能直接到達的)頂點的路徑長度設爲無窮大。初始時,集合T只有頂點s。然後,從dis數組選擇最小值,則該值就是源點s到該值對應的頂點的最短路徑,並且把該點加入到T中,此時完成一個頂點, 然後,我們需要看看新加入的頂點是否可以到達其他頂點並且看看通過該頂點到達其他點的路徑長度是否比源點直接到達短,如果是,那麼就替換這些頂點在dis中的值。 然後,又從dis中找出最小值,重複上述動作,直到T中包含了圖的所有頂點。

不同於普通的貪心算法維護一個局部最優值,Dijkstra算法維護的局部最優值是一個數組

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章