• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-48  評(píng)論-259  文章-1  trackbacks-0

            一.貪心算法的基本概念

                當(dāng)一個(gè)問題具有最優(yōu)子結(jié)構(gòu)性質(zhì)時(shí),我們會(huì)想到用動(dòng)態(tài)規(guī)劃法去解它。但有時(shí)會(huì)有更簡單有效的算法。我們來看一個(gè)找硬幣的例子。假設(shè)有四種硬幣,它們的面值分別為二角五分、一角、五分和一分。現(xiàn)在要找給某顧客六角三分錢。這時(shí),我們會(huì)不假思索地拿出2個(gè)二角五分的硬幣,1個(gè)一角的硬幣和3個(gè)一分的硬幣交給顧客。這種找硬幣方法與其他的找法相比,所拿出的硬幣個(gè)數(shù)是最少的。這里,我們下意識(shí)地使用了這樣的找硬幣算法:首先選出一個(gè)面值不超過六角三分的最大硬幣,即二角五分;然后從六角三分中減去二角五分,剩下三角八分;再選出一個(gè)面值不超過三角八分的最大硬幣,即又一個(gè)二角五分,如此一直做下去。這個(gè)找硬幣的方法實(shí)際上就是貪心算法。顧名思義,貪心算法總是作出在當(dāng)前看來是最好的選擇。也就是說貪心算法并不從整體最優(yōu)上加以考慮,它所作出的選擇只是在某種意義上的局部最優(yōu)選擇。當(dāng)然,我們希望貪心算法得到的最終結(jié)果也是整體最優(yōu)的。上面所說的找硬幣算法得到的結(jié)果就是一個(gè)整體最優(yōu)解。找硬幣問題本身具有最優(yōu)子結(jié)構(gòu)性質(zhì),它可以用動(dòng)態(tài)規(guī)劃算法來解。但我們看到,用貪心算法更簡單,更直接且解題效率更高。這利用了問題本身的一些特性。例如,上述找硬幣的算法利用了硬幣面值的特殊性。如果硬幣的面值改為一分、五分和一角一分3種,而要找給顧客的是一角五分錢。還用貪心算法,我們將找給顧客1個(gè)一角一分的硬幣和4個(gè)一分的硬幣。然而3個(gè)五分的硬幣顯然是最好的找法。雖然貪心算法不是對(duì)所有問題都能得到整體最優(yōu)解,但對(duì)范圍相當(dāng)廣的許多問題它能產(chǎn)生整體最優(yōu)解。如圖的單源最短路徑問題,最小生成樹問題等。在一些情況下,即使貪心算法不能得到整體最優(yōu)解,但其最終結(jié)果卻是最優(yōu)解的很好的近似解。

            二.求解活動(dòng)安排問題算法

                活動(dòng)安排問題是可以用貪心算法有效求解的一個(gè)很好的例子。該問題要求高效地安排一系列爭用某一公共資源的活動(dòng)。貪心算法提供了一個(gè)簡單、漂亮的方法使得盡可能多的活動(dòng)能兼容地使用公共資源。

                設(shè)有n個(gè)活動(dòng)的集合e={1,2,…,n},其中每個(gè)活動(dòng)都要求使用同一資源,如演講會(huì)場等,而在同一時(shí)間內(nèi)只有一個(gè)活動(dòng)能使用這一資源。每個(gè)活動(dòng)i都有一個(gè)要求使用該資源的起始時(shí)間si和一個(gè)結(jié)束時(shí)間fi,且si<fi。如果選擇了活動(dòng)i,則它在半開時(shí)間區(qū)間[si,fi]內(nèi)占用資源。若區(qū)間[si,fi]與區(qū)間[sj,fj]不相交,則稱活動(dòng)i與活動(dòng)j是相容的。也就是說,當(dāng)si≥fi或sj≥fj時(shí),活動(dòng)i與活動(dòng)j相容。活動(dòng)安排問題就是要在所給的活動(dòng)集合中選出最大的相容活動(dòng)子集合。

                在下面所給出的解活動(dòng)安排問題的貪心算法gpeedyselector中,各活動(dòng)的起始時(shí)間和結(jié)束時(shí)間存儲(chǔ)于數(shù)組s和f{中且按結(jié)束時(shí)間的非減序:.f1≤f2≤…≤fn排列。如果所給出的活動(dòng)未按此序排列,我們可以用o(nlogn)的時(shí)間將它重排。

            template< class type>

            void greedyselector(int n, type s[ 1, type f[ ], bool a[ ] ]

             { a[ 1 ] = true;

             int j = 1;

             for (int i=2;i< =n;i+ + ) {

                 if (s[i]>=f[j]) {

                    a[i] = true;

                    j=i;

            }

            else a[i]= false;

            }

            }

                算法greedyselector中用集合a來存儲(chǔ)所選擇的活動(dòng)。活動(dòng)i在集合a中,當(dāng)且僅當(dāng)a[i]的值為true。變量j用以記錄最近一次加入到a中的活動(dòng)。由于輸入的活動(dòng)是按其結(jié)束時(shí)間的非減序排列的,fj總是當(dāng)前集合a中所有活動(dòng)的最大結(jié)束時(shí)間,即:

                 

                貪心算法greedyselector一開始選擇活動(dòng)1,并將j初始化為1。然后依次檢查活動(dòng)i是否與當(dāng)前已選擇的所有活動(dòng)相容。若相容則將活動(dòng)i加人到已選擇活動(dòng)的集合a中,否則不選擇活動(dòng)i,而繼續(xù)檢查下一活動(dòng)與集合a中活動(dòng)的相容性。由于fi

            總是當(dāng)前集合a中所有活動(dòng)的最大結(jié)束時(shí)間,故活動(dòng)i與當(dāng)前集合a中所有活動(dòng)相容的充分且必要的條件是其開始時(shí)間s 不早于最近加入集合a中的活動(dòng)j的結(jié)束時(shí)間fj,si≥fj。若活動(dòng)i與之相容,則i成為最近加人集合a中的活動(dòng),因而取代活動(dòng)j的位置。由于輸人的活動(dòng)是以其完成時(shí)間的非減序排列的,所以算法greedyselector每次總是選擇具有最早完成時(shí)間的相容活動(dòng)加入集合a中。直觀上按這種方法選擇相容活動(dòng)就為未安排活動(dòng)留下盡可能多的時(shí)間。也就是說,該算法的貪心選擇的意義是使剩余的可安排時(shí)間段極大化,以便安排盡可能多的相容活動(dòng)。算法greedyselector的效率極高。當(dāng)輸人的活動(dòng)已按結(jié)束時(shí)間的非減序排列,算法只需g(n)的時(shí)間來安排n個(gè)活動(dòng),使最多的活動(dòng)能相容地使用公共資源。

            例:設(shè)待安排的11個(gè)活動(dòng)的開始時(shí)間和結(jié)束時(shí)間按結(jié)束時(shí)間的非減序排列如下:

            i

            1

            2

            3

            4

            5

            6

            7

            8

            9

            10

            11

            s[i]

            1

            3

            0

            5

            3

            5

            6

            8

            8

            2

            12

            f[i]

            4

            5

            6

            7

            8

            9

            10

            11

            12

            13

            14

             

            算法greedyselector的計(jì)算過程如圖所示。

             

                圖中每行相應(yīng)于算法的一次迭代。陰影長條表示的活動(dòng)是已選人集合a中的活動(dòng),而空白長條表示的活動(dòng)是當(dāng)前正在檢查其相容性的活動(dòng)。若被檢查的活動(dòng)i的開始時(shí)間si小于最近選擇的活動(dòng)了的結(jié)束時(shí)間fj,則不選擇活動(dòng)i,否則選擇活動(dòng)i加入集合a中。

            三.算法分析

                貪心算法并不總能求得問題的整體最優(yōu)解。但對(duì)于活動(dòng)安排問題,貪心算法greedyse—1ector卻總能求得的整體最優(yōu)解,即它最終所確定的相容活動(dòng)集合a的規(guī)模最大。我們可以用數(shù)學(xué)歸納法來證明這個(gè)結(jié)論。

                事實(shí)上,設(shè)e={1,2,…,n}為所給的活動(dòng)集合。由于正中活動(dòng)按結(jié)束時(shí)間的非減序排列,故活動(dòng)1具有最早的完成時(shí)間。首先我們要證明活動(dòng)安排問題有一個(gè)最優(yōu)解以貪心選擇開始,即該最優(yōu)解中包含活動(dòng)1。設(shè) 是所給的活動(dòng)安排問題的一個(gè)最優(yōu)解,且a中活動(dòng)也按結(jié)束時(shí)間非減序排列,a中的第一個(gè)活動(dòng)是活動(dòng)k。若k=1,則a就是一個(gè)以貪心選擇開始的最優(yōu)解。若k>1,則我們設(shè) 。由于f1≤fk,且a中活動(dòng)是互為相容的,故b中的活動(dòng)也是互為相容的。又由于b中活動(dòng)個(gè)數(shù)與a中活動(dòng)個(gè)數(shù)相同,且a是最優(yōu)的,故b也是最優(yōu)的。也就是說b是一個(gè)以貪心選擇活動(dòng)1開始的最優(yōu)活動(dòng)安排。因此,我們證明了總存在一個(gè)以貪心選擇開始的最優(yōu)活動(dòng)安排方案。

                進(jìn)一步,在作了貪心選擇,即選擇了活動(dòng)1后,原問題就簡化為對(duì)e中所有與活動(dòng)1相容的活動(dòng)進(jìn)行活動(dòng)安排的子問題。即若a是原問題的一個(gè)最優(yōu)解,則a=a—{i}是活動(dòng)安排問題 的一個(gè)最優(yōu)解。事實(shí)上,如果我們能找到e的一個(gè)解b,它包含比a更多的活動(dòng),則將活動(dòng)1加入到b中將產(chǎn)生e的一個(gè)解b,它包含比a更多的活動(dòng)。這與a的最優(yōu)性矛盾。因此,每一步所作的貪心選擇都將問題簡化為一個(gè)更小的與原問題具有相同形式的子問題。對(duì)貪心選擇次數(shù)用數(shù)學(xué)歸納法即知,貪心算法greedyselector最終產(chǎn)生原問題的一個(gè)最優(yōu)解。

            四.貪心算法的基本要素

                貪心算法通過一系列的選擇來得到一個(gè)問題的解。它所作的每一個(gè)選擇都是當(dāng)前狀態(tài)下某種意義的最好選擇,即貪心選擇。希望通過每次所作的貪心選擇導(dǎo)致最終結(jié)果是問題的一個(gè)最優(yōu)解。這種啟發(fā)式的策略并不總能奏效,然而在許多情況下確能達(dá)到預(yù)期的目的。解活動(dòng)安排問題的貪心算法就是一個(gè)例子。下面我們著重討論可以用貪心算法求解的問題的一般特征。

                對(duì)于一個(gè)具體的問題,我們怎么知道是否可用貪心算法來解此問題,以及能否得到問題的一個(gè)最優(yōu)解呢?這個(gè)問題很難給予肯定的回答。但是,從許多可以用貪心算法求解的問題中

            我們看到它們一般具有兩個(gè)重要的性質(zhì):貪心選擇性質(zhì)最優(yōu)子結(jié)構(gòu)性質(zhì)

            1.貪心選擇性質(zhì)

                所謂貪心選擇性質(zhì)是指所求問題的整體最優(yōu)解可以通過一系列局部最優(yōu)的選擇,即貪心選擇來達(dá)到。這是貪心算法可行的第一個(gè)基本要素,也是貪心算法與動(dòng)態(tài)規(guī)劃算法的主要區(qū)別。在動(dòng)態(tài)規(guī)劃算法中,每步所作的選擇往往依賴于相關(guān)子問題的解。因而只有在解出相關(guān)子問題后,才能作出選擇。而在貪心算法中,僅在當(dāng)前狀態(tài)下作出最好選擇,即局部最優(yōu)選擇。然后再去解作出這個(gè)選擇后產(chǎn)生的相應(yīng)的子問題。貪心算法所作的貪心選擇可以依賴于以往所作過的選擇,但決不依賴于將來所作的選擇,也不依賴于子問題的解。正是由于這種差別,動(dòng)態(tài)規(guī)劃算法通常以自底向上的方式解各子問題,而貪心算法則通常以自頂向下的方式進(jìn)行,以迭代的方式作出相繼的貪心選擇,每作一次貪心選擇就將所求問題簡化為一個(gè)規(guī)模更小的子問題。

            對(duì)于一個(gè)具體問題,要確定它是否具有貪心選擇性質(zhì),我們必須證明每一步所作的貪心選擇最終導(dǎo)致問題的一個(gè)整體最優(yōu)解。通常可以用我們在證明活動(dòng)安排問題的貪心選擇性質(zhì)時(shí)所采用的方法來證明。首先考察問題的一個(gè)整體最優(yōu)解,并證明可修改這個(gè)最優(yōu)解,使其以貪心選擇開始。而且作了貪心選擇后,原問題簡化為一個(gè)規(guī)模更小的類似子問題。然后,用數(shù)學(xué)歸納法證明,通過每一步作貪心選擇,最終可得到問題的一個(gè)整體最優(yōu)解。其中,證明貪心選擇后的問題簡化為規(guī)模更小的類似子問題的關(guān)鍵在于利用該問題的最優(yōu)子結(jié)構(gòu)性質(zhì)。

            2.最優(yōu)子結(jié)構(gòu)性質(zhì)

                當(dāng)一個(gè)問題的最優(yōu)解包含著它的子問題的最優(yōu)解時(shí),稱此問題具有最優(yōu)子結(jié)構(gòu)性質(zhì)。問題所具有的這個(gè)性質(zhì)是該問題可用動(dòng)態(tài)規(guī)劃算法或貪心算法求解的一個(gè)關(guān)鍵特征。在活動(dòng)安排問題中,其最優(yōu)子結(jié)構(gòu)性質(zhì)表現(xiàn)為:若a是對(duì)于正的活動(dòng)安排問題包含活動(dòng)1的一個(gè)最優(yōu)解,則相容活動(dòng)集合a=a—{1}是對(duì)于e={i∈e:si≥f1}的活動(dòng)安排問題的一個(gè)最優(yōu)解。

            3.貪心算法與動(dòng)態(tài)規(guī)劃算法的差異

                貪心算法和動(dòng)態(tài)規(guī)劃算法都要求問題具有最優(yōu)子結(jié)構(gòu)性質(zhì),這是兩類算法的一個(gè)共同點(diǎn)。但是,對(duì)于一個(gè)具有最優(yōu)子結(jié)構(gòu)的問題應(yīng)該選用貪心算法還是動(dòng)態(tài)規(guī)劃算法來求解?是不是能用動(dòng)態(tài)規(guī)劃算法求解的問題也能用貪心算法來求解?下面我們來研究兩個(gè)經(jīng)典的組合優(yōu)化問題,并以此來說明貪心算法與動(dòng)態(tài)規(guī)劃算法的主要差別。

            五. 0-背包問題

            給定n種物品和一個(gè)背包。物品i的重量是w ,其價(jià)值為v ,背包的容量為c.問應(yīng)如何選擇裝入背包中的物品,使得裝入背包中物品的總價(jià)值最大? 在選擇裝入背包的物品時(shí),對(duì)每種物品i只有兩種選擇,即裝入背包或不裝入背包。不能將物品i裝入背包多次,也不能只裝入部分的物品i。

                此問題的形式化描述是,給定c>0,wi>0,vi>0,1≤i≤n,要求找出一個(gè)n元0—1向

            (xl,x2,…,xn), ,使得 ≤c,而且 達(dá)到最大。

                  背包問題:與0-1背包問題類似,所不同的是在選擇物品i裝入背包時(shí),可以選擇物品i的一部分,而不一定要全部裝入背包。

                此問題的形式化描述是,給定c>0,wi>0,vi>0,1≤i≤n,要求找出一個(gè)n元向量

            (x1,x2,...xn),0≤xi≤1,1≤i≤n 使得 ≤c,而且 達(dá)到最大。

                這兩類問題都具有最優(yōu)子結(jié)構(gòu)性質(zhì)。對(duì)于0—1背包問題,設(shè)a是能夠裝入容量為c的背包的具有最大價(jià)值的物品集合,則aj=a-{j}是n-1個(gè)物品1,2,…,j—1,j+1,…,n可裝入容量為c-wi叫的背包的具有最大價(jià)值的物品集合。對(duì)于背包問題,類似地,若它的一個(gè)最優(yōu)解包含物品j,則從該最優(yōu)解中拿出所含的物品j的那部分重量wi,剩余的將是n-1個(gè)原重物品1,2,…,j-1,j+1,…,n以及重為wj-wi的物品j中可裝入容量為c-w的背包且具有最大價(jià)值的物品。

                雖然這兩個(gè)問題極為相似,但背包問題可以用貪心算法求解,而0·1背包問題卻不能用貪心算法求解。用貪心算法解背包問題的基本步驟是,首先計(jì)算每種物品單位重量的價(jià)值

            vj/wi然后,依貪心選擇策略,將盡可能多的單位重量價(jià)值最高的物品裝入背包。若將這種物品全部裝入背包后,背包內(nèi)的物品總重量未超過c,則選擇單位重量價(jià)值次高的物品并盡可能多地裝入背包。依此策略一直進(jìn)行下去直到背包裝滿為止。具體算法可描述如下:

             void knapsack(int n, float m, float v[ ], float w[ ], float x[ ] )

             sort(n,v,w);

             int i;

             for(i= 1;i<= n;i++) x[i] = o;

             float c = m;

             for (i = 1;i < = n;i ++) {

                 if (w[i] > c) break;

                x[i] = 1;

                c-= w[i];

                }

             if (i < = n) x[i] = c/w[i];

            算法knapsack的主要計(jì)算時(shí)間在于將各種物品依其單位重量的價(jià)值從大到小排序。因此,算法的計(jì)算時(shí)間上界為o(nlogn)。當(dāng)然,為了證明算法的正確性,我們還必須證明背包問題具有貪心選擇性質(zhì)。 

            這種貪心選擇策略對(duì)0—1背包問題就不適用了。看圖2(a)中的例子,背包的容量為50千克;物品1重10千克;價(jià)值60元;物品2重20千克,價(jià)值100元;物品3重30千克;價(jià)值120元。因此,物品1每千克價(jià)值6元,物品2每千克價(jià)值5元,物品3每千克價(jià)值4元。若依貪心選擇策略,應(yīng)首選物品1裝入背包,然而從圖4—2(b)的各種情況可以看出,最優(yōu)的選擇方案是選擇物品2和物品3裝入背包。首選物品1的兩種方案都不是最優(yōu)的。對(duì)于背包問題,貪心選擇最終可得到最優(yōu)解,其選擇方案如圖2(c)所示。

             

                對(duì)于0—1背包問題,貪心選擇之所以不能得到最優(yōu)解是因?yàn)樗鼰o法保證最終能將背包裝滿,部分背包空間的閑置使每千克背包空間所具有的價(jià)值降低了。事實(shí)上,在考慮0—1背包問題的物品選擇時(shí),應(yīng)比較選擇該物品和不選擇該物品所導(dǎo)致的最終結(jié)果,然后再作出最好選擇。由此就導(dǎo)出許多互相重疊的于問題。這正是該問題可用動(dòng)態(tài)規(guī)劃算法求解的另一重要特征。動(dòng)態(tài)規(guī)劃算法的確可以有效地解0—1背包問題。

             

            posted on 2007-06-16 11:40 星夢情緣 閱讀(31602) 評(píng)論(6)  編輯 收藏 引用 所屬分類: 關(guān)于編程

            評(píng)論:
            # re: 貪心算法精講 2010-10-31 15:34 | 老棟
            請注意這里:若區(qū)間[si,fi]與區(qū)間[sj,fj]不相交,則稱活動(dòng)i與活動(dòng)j是相容的。也就是說,當(dāng)si≥fi或sj≥fj時(shí),活動(dòng)i與活動(dòng)j相容。

            當(dāng)si≥fi或sj≥fj時(shí),活動(dòng)i與活動(dòng)j相容。博主再好好想想,這里是不是有問題?  回復(fù)  更多評(píng)論
              
            # re: 貪心算法精講 2011-02-22 21:50 | legendtkl
            @老棟
            恩,是有點(diǎn)問題
              回復(fù)  更多評(píng)論
              
            # re: 貪心算法精講 2011-07-15 10:11 | hfrzhanghao
            講的很詳盡,謝謝!  回復(fù)  更多評(píng)論
              
            # re: 貪心算法精講 2011-08-31 15:26 | jc_ontheroad
            學(xué)習(xí)了,講得很詳細(xì)。  回復(fù)  更多評(píng)論
              
            # re: 貪心算法精講 2011-12-08 16:16 | 孫磊磊
            謝謝作者分享,不過文中有幾處筆誤啊,  回復(fù)  更多評(píng)論
              
            # re: 貪心算法精講[未登錄] 2013-06-07 14:31 | wang
            好,不錯(cuò)~  回復(fù)  更多評(píng)論
              
            国产精品久久久天天影视| 国内精品久久久久久久影视麻豆 | 精品熟女少妇AV免费久久| 亚洲欧美伊人久久综合一区二区| 久久久久人妻精品一区 | 亚洲级αV无码毛片久久精品| WWW婷婷AV久久久影片| 人人狠狠综合88综合久久| 久久精品蜜芽亚洲国产AV| 欧洲性大片xxxxx久久久| 国产精品久久一区二区三区| 综合久久一区二区三区 | 欧美日韩精品久久免费| 国产精品久久久久影院色| 亚洲欧洲精品成人久久奇米网| 国产精品美女久久久| 久久久一本精品99久久精品88| 国产精品无码久久四虎| 99国产欧美久久久精品蜜芽 | 色欲综合久久中文字幕网| 精品无码久久久久久国产| 久久婷婷国产麻豆91天堂| 久久亚洲精品成人av无码网站| 久久综合九色综合久99| 88久久精品无码一区二区毛片| 久久久久女人精品毛片| 亚洲精品tv久久久久久久久| 色综合久久夜色精品国产| 人妻丰满?V无码久久不卡| 精品熟女少妇aⅴ免费久久| 久久精品一区二区国产| 国内精品久久久人妻中文字幕| 亚洲国产精品无码久久久不卡| 久久天天婷婷五月俺也去| 欧美激情精品久久久久久久| 国产精品日韩欧美久久综合| 2020最新久久久视精品爱| 亚洲狠狠综合久久| 国产精品久久久久乳精品爆| 久久久久久狠狠丁香| 国产一区二区三精品久久久无广告|