貪心演算法詳解

2021-08-07 04:30:56 字數 4091 閱讀 6787

一、簡介

1.1 貪心演算法基本思想

貪心演算法(又稱貪婪演算法)是指,在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,他所做出的是在某種意義上的區域性最優解。

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

1.2 貪心演算法跟動態規劃的區別

貪心演算法中「貪心」二字形象的說明了該演算法的基本思想:貪心(每一步選擇都是眼下的區域性最優選擇)。比如每次給你1張面額不定的紙幣,共10次,你這麼選?肯定是每次都要一張100元的。當你要拿第一張時,此時眼下最優的選擇就是拿一張100的,不會管拿了之後會不會對後面的9張產生影響。這就是一種貪心,當然這種情況下的貪心選擇也是最優的選擇,因為區域性最優導致了整體的最優。

貪心演算法常用於求解最優解問題,比動態規劃思路簡單,前提是要求問題滿足貪心選擇性質。

形象的講:貪心演算法的每次選擇就是只看當前的利益,不管當前的選擇對後面選擇的影響,所以如果當前的選擇對之後的選擇有影響時,這種選擇就不一定最優了。

而動態規劃就是三思而後行,在考慮當前選擇能產生的各種結果中選擇乙個最優的,想得多速度也就慢了。比如上面的例子,如果規定超過2張100,後面每張就都只會給1元的,那麼按照貪心選擇依然會前兩張選擇100的,後面就只能拿1元的,總共208元。按照動態規劃,則會聰明的先選一張100元,後面每次都選擇50元,總共550元。

二、貪心演算法的基本要素

1、貪心選擇

貪心選擇是指所求問題的整體最優解可以通過一系列區域性最優的選擇,即貪心選擇來達到。這是貪心演算法可行的第乙個基本要素,也是貪心演算法與動態規劃演算法的主要區別。貪心選擇是採用從頂向下、以迭代的方法做出相繼選擇,每做一次貪心選擇就將所求問題簡化為乙個規模更小的子問題。對於乙個具體問題,要確定它是否具有貪心選擇的性質,我們必須證明每一步所作的貪心選擇最終能得到問題的最優解。通常可以首先證明問題的乙個整體最優解,是從貪心選擇開始的,而且作了貪心選擇後,原問題簡化為乙個規模更小的類似子問題。然後,用數學歸納法證明,通過每一步貪心選擇,最終可得到問題的乙個整體最優解。

2、最優子結構

當乙個問題的最優解包含其子問題的最優解時,稱此問題具有最優子結構性質。運用貪心策略在每一次轉化時都取得了最優解。問題的最優子結構性質是該問題可用貪心演算法或動態規劃演算法求解的關鍵特徵。貪心演算法的每一次操作都對結果產生直接影響,而動態規劃則不是。貪心演算法對每個子問題的解決方案都做出選擇,不能回退;動態規劃則會根據以前的選擇結果對當前進行選擇,有回退功能。動態規劃主要運用於二維或三維問題,而貪心一般是一維問題。

三、貪心演算法的主要步驟

(1)建立數學模型來描述問題;

(2)把求解的問題分成若干個子問題;

(3)對每一子問題求解,得到子問題的區域性最優解;

(4)把子問題的解區域性最優解合成原來解問題的乙個解。

四、例題分析

下面是乙個可以試用貪心演算法解的題目,貪心解的確不錯,可惜不是最優解。

揹包問題:

有乙個揹包,揹包容量是m=150。有7個物品,物品可以分割成任意大小。要求盡可能讓裝入揹包中的物品總價值最大,但不能超過總容量。

物品 a b c d e f g

重量 35 30 60 50 40 10 25

價值 10 40 30 50 35 40 30

分析:

目標函式: ∑pi最大

約束條件是裝入的物品總重量不超過揹包容量:∑wi<=m( m=150)

優化策略:

(1)根據貪心的策略,每次挑選價值最大的物品裝入揹包,得到的結果是否最優?

(2)每次挑選所佔重量最小的物品裝入是否能得到最優解?

(3)每次選取單位重量價值最大的物品,成為解本題的策略。

值得注意的是,貪心演算法並不是完全不可以使用,貪心策略一旦經過證明成立後,它就是一種高效的演算法。

貪心演算法還是很常見的演算法之一,這是由於它簡單易行,構造貪心策略不是很困難。

可惜的是,它需要證明後才能真正運用到題目的演算法中。

一般來說,貪心演算法的證明圍繞著:整個問題的最優解一定由在貪心策略中存在的子問題的最優解得來的。

對於例題中的3種貪心策略,都是無法成立(無法被證明)的,具體原因如下:

(1)貪心策略:選取價值最大者。反例:

w=30

物品:a b c

重量:28 12 12

價值:30 20 20

根據策略,首先選取物品a,接下來就無法再選取了,可是,選取b、c則更好。

(2)貪心策略:選取重量最小。它的反例與第一種策略的反例差不多。

(3)貪心策略:選取單位重量價值最大的物品。反例:

w=30

物品:a b c

重量:28 20 10

價值:28 20 10

根據策略,三種物品單位重量價值一樣,程式無法依據現有策略作出判斷,如果選擇a,則答案錯誤。

五、leetcode中關於貪心演算法的例項

5.1 jump game

(1)題意

給你乙個陣列,陣列的每個元素表示你能前進的最大步數,最開始時你在第乙個元素所在的位置,之後你可以前進,問能不能到達最後乙個元素位置。例如:a = [2, 3, 1, 1, 4], return true。此時一種走法是 0 - 2 - 3 - 4,還有一種走法是 0 - 1 – 4。

(2)解題思路

使用貪心演算法,不管每一步怎麼跳,我都跳到最後,跳到不能跳為止。 比如我們用乙個變數max_reach,來記錄我能跳到的最後的位置。對第i步來說,從第i個位置出發的最遠是nums[i]+i那麼我們的max_reach =max(max_reach,nums[i]+i) 如果在某一步i>g,也就是說,前面能跳到的最遠距離跳不到i,那就肯定失敗。 如果最終能跳到最後一步就返回成功。

(3)python**

class

solution

(object):

defcanjump

(self, nums):

max_reach, n = 0, len(nums)

for i, x in enumerate(nums):

if max_reach < i:

return

false

if max_reach >= n - 1:

return

true

max_reach = max(max_reach, i + x)

5.2 container with most water

(1)題目

在二維座標系中,(i, ai) 表示 從 (i, 0) 到 (i, ai) 的一條線段,任意兩條這樣的線段和 x 軸組成乙個木桶,找出能夠盛水最多的木桶,返回其容積。

(2)解題思路

用兩個指標從兩端開始向中間靠攏,如果左端線段短於右端,那麼左端右移,反之右端左移,知道左右兩端移到中間重合,記錄這個過程中每一次組成木桶的容積,返回其中最大的。

合理性解釋:當左端線段l小於右端線段r時,我們把l右移,這時捨棄的是l與右端其他線段(r-1, r-2, …)組成的木桶,這些木桶是沒必要判斷的,因為這些木桶的容積肯定都沒有l和r組成的木桶容積大。這是因為木桶的容積由l和r的最小值和(i-j)所決定,兩段取其小有效。

(3)python**

class

solution

(object):

defmaxarea

(self, height):

size=len(height)

maxm=0

j=0k=size-1

while jif height[j]<=height[k]:

maxm=max(maxm,height[j]*(k-j))

j+=1

else:

maxm=max(maxm,height[k]*(k-j))

k-=1

return maxm

六、用貪心演算法實現的經典例項

(1)揹包問題(物體可切分時的0-1揹包問題);

(2)huffman編碼;

(3)單源最短路徑;

(4)prim演算法;

(5)kruskal演算法;

(6)最優三角剖分。

貪心演算法詳解

一 基本概念 所謂貪心演算法是指,在對問題求解時,總是做出在當前看來是最好的選擇 也就是說,不從整體最優上加以考慮,他所做出的僅是在某種意義上的區域性最優解。貪心演算法沒有固定的演算法框架,演算法設計的關鍵是貪心策略的選擇。必須注意的是,貪心演算法不是對所有問題都能得到整體最優解,選擇的貪心策略必須...

貪心演算法詳解

貪心演算法 總是作出當前看來最好的選擇。也就是說貪心演算法並不從整體最優考慮,他所做出的選擇只是在某種意義上的區域性最優選擇。但對許多問題它能產生整體最優解。在一些情況下,即使貪心演算法不能得到整體最優解,其最終結果卻是最優解的很好近似。應用貪心思想的常用問題 單源最短路徑問題,最小生成樹問題,哈夫...

經典貪心演算法 貪心演算法概述

貪心演算法具有最優子問題結構,它的特點是 短視 每次選擇對當前局面最有利的決策,來一步步獲得最優解。我個人認為,貪心不是乙個具體的方法,而是一類方法,貪心演算法的關鍵不在於想到,而在於正確性的證明。要證明乙個貪心演算法是正確的,需要證明我們可以把乙個最優解逐步轉化為我們用貪心演算法所得到的解,而解不...