資源簡(jiǎn)介 貪心算法在實(shí)際生活中,經(jīng)常需要求一個(gè)問(wèn)題的可行解和最優(yōu)解,這就是所謂的最優(yōu)化問(wèn)題。每個(gè)最優(yōu)化問(wèn)題都包含一組限制條件和一個(gè)優(yōu)化函數(shù),符合限制條件的問(wèn)題求解方案稱(chēng)為可行解,使優(yōu)化函數(shù)取得最佳值的可行解稱(chēng)為最優(yōu)解。貪心法是求解這類(lèi)問(wèn)題的一種常用算法,它是從問(wèn)題的某一個(gè)初始解出發(fā),采用逐步構(gòu)造最優(yōu)解的方法向給定的目標(biāo)前進(jìn)。在每個(gè)局部階段,都做出一個(gè)看上去最優(yōu)的決策(即某種意義下的、或某個(gè)標(biāo)準(zhǔn)下的局部最優(yōu)解),并期望通過(guò)每次所做的局部最優(yōu)選擇產(chǎn)生出一個(gè)全局最優(yōu)解。但采用貪心法求解不能保證對(duì)所有問(wèn)題都能得到最優(yōu)解,這時(shí)我們可以選擇其它解決最優(yōu)化問(wèn)題的算法,如動(dòng)態(tài)規(guī)劃等。做出貪心決策的依據(jù)稱(chēng)為貪心準(zhǔn)則(策略),注意決策一旦做出,就不可再更改。貪心與遞推不同的是,推進(jìn)的每一步不是依據(jù)某一固定的遞推式,而是做一個(gè)當(dāng)時(shí)看似最佳的貪心選擇(操作),不斷地將問(wèn)題實(shí)例歸納為更小的相似子問(wèn)題。所以,歸納、分析、選擇正確合適的貪心準(zhǔn)則,是正確解決貪心問(wèn)題的關(guān)鍵。下面我們先看兩個(gè)簡(jiǎn)單而典型的例子。例 1、刪數(shù)問(wèn)題[問(wèn)題描述] 鍵盤(pán)輸入一個(gè)高精度的正整數(shù) n(≤240 位),去掉其中任意 s個(gè)數(shù)字后剩下的數(shù)字按原左右次序?qū)⒔M成一個(gè)新的正整數(shù)。編程對(duì)給定的 n 和 s,尋找一種方案,使得剩下的數(shù)字組成的新數(shù)最小。[輸入格式] ns[輸出格式] 最后剩下的最小數(shù)。[樣例輸入] 1785434[樣例輸出] 13[算法分析]由于正整數(shù) n 的有效數(shù)位為 240 位,所以很自然地采用字符串類(lèi)型存貯 n。那么如何決定哪 s位被刪除呢?是不是最大的 s個(gè)數(shù)字呢?顯然不是,大家很容易舉出一些反例。為了盡可能逼近目標(biāo),我們選取的貪心策略為:每一步總是選擇一個(gè)使剩下的數(shù)最小的數(shù)字刪去,即按高位到低位的順序搜索,若各位數(shù)字遞增,則刪除最后一個(gè)數(shù)字;否則刪除第一個(gè)遞減區(qū)間的首字符,這樣刪一位便形成了一個(gè)新數(shù)字串。然后回到串首,按上述規(guī)則再刪下一個(gè)數(shù)字。重復(fù)以上過(guò)程 s次為止,剩下的數(shù)字串便是問(wèn)題的解了。例如:n=178543s=4刪數(shù)的過(guò)程如下:n=178543 {刪掉 8}17543 {刪掉 7}1543 {刪掉 5}127143 {刪掉 4}13 {解為 13}這樣,刪數(shù)問(wèn)題就與如何尋找遞減區(qū)間首字符這樣一個(gè)簡(jiǎn)單的問(wèn)題對(duì)應(yīng)起來(lái)。不過(guò)還要注意一個(gè)細(xì)節(jié)性的問(wèn)題,就是可能會(huì)出現(xiàn)字符串串首有若干 0的情況,甚至整個(gè)字符串都是0的情況。按以上貪心策略編制的程序框架如下:輸入 n,s;while s>0 dobegini:=1; {從串首開(kāi)始找}while (idelete (n,i,1); {刪除字符串 n的第 i個(gè)字符}s:=s-1;end;while (length(n)>1)and (n[1]=‘0’) do delete(n,1,1);{刪去串首可能產(chǎn)生的無(wú)用零}輸出 n;例 2、取數(shù)游戲[問(wèn)題描述] 給出 2*n(n<=100)個(gè)自然數(shù)(數(shù)小于等于 30000)。游戲雙方分別為 A方(計(jì)算機(jī)方)和 B方(對(duì)奕的人)。只允許從數(shù)列兩頭取數(shù)。A先取,然后雙方依次輪流取數(shù)。取完時(shí),誰(shuí)取得的數(shù)字總和最大為取勝方;雙方和相等,屬于 A勝。試問(wèn) A方可否有必勝的策略?[輸入格式] 鍵盤(pán)輸入 n及 2*n 個(gè)自然數(shù)。[輸出格式] 共 3*n+2 行,其中前 3*n 行為游戲經(jīng)過(guò)。每 3 行分別為 A 方所取的數(shù)和 B方所取的數(shù),及 B方取數(shù)前應(yīng)給予的適當(dāng)提示,讓游戲者選擇取哪一頭的數(shù)(L/R—左端或右端)。最后 2行分別為 A方取得的數(shù)和和 B方取得的數(shù)和。[算法分析]設(shè) n=4,自然數(shù)列為:7 9 3 6 4 2 5 3,我們?cè)O(shè)計(jì)一種原始的貪心策略,讓 A每次取數(shù)列兩頭較大的那個(gè)數(shù),則游戲者也不會(huì)傻,他也會(huì)這么干,所以在上面的數(shù)列中,A方會(huì)順序取 7、3、4、5,B方會(huì)順序取 9、6、2、3,由此得出:A方取得的數(shù)和為 7+3+4+5=19,B方取得的數(shù)和為 9+6+2+3=20,按照規(guī)則,判定 A方輸。其實(shí),如果按上述貪心策略去游戲,成敗取決于給你的測(cè)試數(shù)據(jù)!不過(guò),雖然 A方敗給B方,但是我們卻發(fā)現(xiàn)了一個(gè)有趣的事實(shí):A方取走偶位置的數(shù)后,剩下兩端數(shù)都處于奇位置;反之,若 A 方取走奇位置的數(shù)后,剩下兩端數(shù)都處于偶位置。即無(wú)論 B 方如何取法,A 方即可以取走奇位置的所有數(shù),亦可以取走偶位置的所有數(shù)。由此萌發(fā)出另一種有效的貪心策略:若能夠讓 A方取走“數(shù)和較大的奇(或偶)位置上的所有數(shù)”,則 A方必勝。這樣,取數(shù)問(wèn)題便對(duì)應(yīng)于一個(gè)簡(jiǎn)單問(wèn)題:讓 A方取奇偶位置中數(shù)和較大的一半數(shù)。設(shè) j為 A取數(shù)的奇偶位置標(biāo)志,則 j=0 表示偶位置數(shù)和較大,A取偶位置上的所有數(shù);j=1 表示奇位置數(shù)和較大,A取奇位置的所有數(shù)。128設(shè) SA,SB 分別表示 A方取數(shù)和,B方取數(shù)和(SA≥SB);a存儲(chǔ) 2*n 個(gè)自然數(shù)序列;lp,rp 為序列的左端位置和右端位置;ch為 B方取數(shù)的位置信息(’L’或’R’);按上述貪心思想編寫(xiě)的程序框架如下:讀入 n及 a;SA:=0;SB:=0; {計(jì)算 A方取數(shù)和、B方取數(shù)和,A方取數(shù)的位置標(biāo)志}for i:=1 to n dobeginSA:=SA+a[2*i-1];SB:=SB+a[2*i];end;if SA>=SB then j:=1else begin j:=0;交換 SA 和 SB;end;lp:=1;rp:=2*n;for i:=1 to n do {A 方和 B方依次進(jìn)行 n次對(duì)奕}beginif ((j=1) and (lp mod 2=1)) or ((j=0)and (lp mod 2=0)) {若 A方應(yīng)取奇位置數(shù)且左端位置為奇,或者 A方應(yīng)取偶位置數(shù)且左端位置為偶,則 A方取走左端位置的數(shù)}then begin writeln(a[lp]);lp:=lp+1;end {輸出}else begin writeln(a[rp]);rp:=rp-1;end;write(‘ B=L/R ’);{提示信息}repeat {B 方取數(shù),輸入 L或 R}readln(ch);if ch=‘L’ then begin write(a[lp]);lp:=lp+1;end; {輸出}if ch=‘R’ then begin writeln(a[rp]);rp:=rp-1;end;until (ch=‘L’) or (ch=‘R’);end;輸出 A 方取數(shù)的和 SA 和 B 方取數(shù)的和 SB;小結(jié):以上兩個(gè)例題所用的貪心思想還是很明顯的,選取的貪心策略也很直觀(可能也是唯一的);不僅能得到最優(yōu)解,而且解的正確性也可以得到嚴(yán)格的證明。但有些問(wèn)題采用貪心法求解時(shí),貪心策略可能有多種,在針對(duì)性不同的測(cè)試數(shù)據(jù)下,帶來(lái)的效果可能也不一樣,并不是總能得到最優(yōu)解,而且解的正確性證明也很困難。最典型的例子就是 0/1 背包問(wèn)題。例3、0/1背包問(wèn)題[問(wèn)題描述] 有一容量為weight的背包?,F(xiàn)在要從n件物品中選取若干裝入背包中,每件物品i的重量為w[i],價(jià)值為p[i]。定義一種可行的背包裝載為:背包中物品的總重量不能超過(guò)背包的容量,并且一個(gè)物品要么全部選取,要么不選取。定義最佳裝載是指所裝入的物品價(jià)值最高,并且是可行的背包裝載。[樣例輸入]11 {weight}1294 {n}2 4 6 7 {w[i]}6 10 12 13 {p[i]}[樣例輸出]0 1 0 123[問(wèn)題分析]設(shè)數(shù)組choice[1..n],若choice[i]=1表示物品i裝入背包中,choice[i]=0表示物品i不裝入背包中。則choice=[0,1,0,1]是一種可行的背包裝載方案,也是一種最佳裝載方案,此時(shí)總價(jià)值為23。0/1 背包問(wèn)題有好幾種貪心準(zhǔn)則,每種貪心準(zhǔn)則都是采用多步過(guò)程來(lái)完成背包的裝入,在每一步過(guò)程中利用某種固定的貪心準(zhǔn)則選擇一個(gè)物品裝入背包。一種貪心準(zhǔn)則為:從剩余的物品中,選出可以裝入背包的價(jià)值最大的物品,利用這種規(guī)則,價(jià)值最大的物品首先被裝入(假設(shè)有足夠容量),然后是下一個(gè)價(jià)值最大的物品,如此繼續(xù)下去。這種貪心準(zhǔn)則不能保證得到最優(yōu)解。例如 weight=105,n=3,w=[100,10,10],p=[20,15,15]。按照以上這種“價(jià)值貪心準(zhǔn)則”,獲得的解為 choice=[1,0,0],這種方案的總價(jià)值為 20。而最優(yōu)解為 choice =[0,1,1],其總價(jià)值為 30。另一種方案是“重量貪心準(zhǔn)則”,即從剩下的物品中選擇可裝入背包的重量最小的物品。雖然這種規(guī)則對(duì)于前面的例子能產(chǎn)生最優(yōu)解,但在一般情況下不一定能得到最優(yōu)解,例如weight=25,n=2,w=[10,20],p=[5,100]。獲得的解為choice=[1,0],總價(jià)值為5,比最優(yōu)解choice =[0,1]的總價(jià)值100要差。本題的另一方案為“單位價(jià)值貪心準(zhǔn)則”,這種方案是從剩余物品中選擇可裝入包的p[i]/w[i]值最大的物品,這種策略也不能保證得到最優(yōu)解。例如weight=30,n=3,w=[20,15,15],p=[40,25,25]。獲得的解為choice=[1,0,0],總價(jià)值為40。而最優(yōu)解為choice=[0,1,1]的總價(jià)值為50。既然任何一種貪心策略都不能保證得到最優(yōu)解,那么本題是不是不應(yīng)該用貪心法?其實(shí)我們不必因所考察的幾個(gè)貪心策略都不能保證得到最優(yōu)解而沮喪(或放棄),因?yàn)?0/1 背包問(wèn)題是一個(gè)復(fù)雜的 NP問(wèn)題。對(duì)于這類(lèi)問(wèn)題,也許根本就不可能找到具有多項(xiàng)式時(shí)間的算法。雖然按“單位價(jià)值貪心準(zhǔn)則”遞減的次序裝入物品不能保證得到最優(yōu)解,但它是一個(gè)直覺(jué)上近似的解,而且時(shí)間復(fù)雜度僅為 O(nlogn)。造成多種貪心都不能全對(duì)的原因其實(shí)在于,在很多情況下,無(wú)法將背包填滿(mǎn),空間上的浪費(fèi)間接降低了實(shí)際上的單位價(jià)值。當(dāng)然本題很有一種思路,就是用動(dòng)態(tài)規(guī)劃求解。小結(jié):與這個(gè)題目類(lèi)似的問(wèn)題很多,比如部分背包問(wèn)題、船的最優(yōu)裝載問(wèn)題、硬幣的最少組合問(wèn)題、多機(jī)調(diào)度問(wèn)題等。留給大家回去思考:哪些可以用貪心法、哪些不可以。例 4、活動(dòng)選擇130[問(wèn)題描述] 假設(shè)有一個(gè)需要使用某一資源的 n個(gè)活動(dòng)組成的集合 S,S={1,……,n}。該資源一次只能被一個(gè)活動(dòng)所占用,每一個(gè)活動(dòng)有一個(gè)開(kāi)始時(shí)間 bi和結(jié)束時(shí)間 ei (bi≤ei)。若 bi≥ej或者 bj≥ei,則活動(dòng) i和活動(dòng) j兼容。你的任務(wù)是:選擇由互相兼容的活動(dòng)組成的最大集合。[輸入格式] 輸入文件名為:act.in,共 n+1 行,其中第 1行為 n,第 2行到第 n+1 行表示 n個(gè)活動(dòng)的開(kāi)始時(shí)間和結(jié)束時(shí)間(中間用空格隔開(kāi)),格式為:nb1 e1………bn en[輸出格式] 輸出文件名為:act.out,共兩行,第 1行為滿(mǎn)足要求的活動(dòng)占用的時(shí)間 t,第 2行為最大集合中的活動(dòng)序號(hào),每個(gè)數(shù)據(jù)之間用一個(gè)空格隔開(kāi)。[樣例輸入]113 51 412 148 120 68 116 105 73 85 92 13[樣例輸出]142 3 6 8[算法分析]我們使用的貪心策略如下,即每一步總是選擇這樣一個(gè)活動(dòng)來(lái)占用資源:它能夠使得余下的未調(diào)度時(shí)間最大化,使得兼容的活動(dòng)盡可能多。為了達(dá)到這個(gè)目的,我們將 n個(gè)待選活動(dòng)按結(jié)束時(shí)間遞增的順序排列:e1’≤e2’≤……≤en’。首先將遞增序列中的活動(dòng)1進(jìn)入集合S。然后依次分析遞增序列中的活動(dòng)2,活動(dòng)3,……,活動(dòng) n,每次將與 S中的活動(dòng)兼容的活動(dòng)加入到集合 S中。我們結(jié)合問(wèn)題的樣例輸入,先將 11 個(gè)活動(dòng)的活動(dòng)號(hào)、開(kāi)始時(shí)間、結(jié)束時(shí)間及遞增編號(hào)列表(表 1)如下:表 1活動(dòng)序號(hào) i 開(kāi)始時(shí)間 b[i] 結(jié)束時(shí)間 e[i] 按活動(dòng)結(jié)束時(shí)間遞增的序號(hào) j1311 3 5 22 1 4 13 12 14 114 8 12 95 0 6 36 8 11 87 6 10 78 5 7 49 3 8 510 5 9 611 2 13 10按照以上這種貪心策略,貪心選擇的過(guò)程如下:時(shí)間 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14選擇活動(dòng) |—|—|—|—|—|—|—|—|—|—|—|—|—|—|2 —————活動(dòng) 2兼容(持續(xù)時(shí)間 1-4),加入 S,S={2},t=41 不兼容,放棄5 不兼容,放棄8 ————活動(dòng) 8兼容(持續(xù)時(shí)間 5-7),加入 S,S={2,8},t=79 不兼容,放棄10 不兼容,放棄7 不兼容,放棄6 —————活動(dòng) 6兼容(持續(xù)時(shí)間 8-11),加入 S,S={2,8,6},t=114 不兼容,放棄11 不兼容,放棄3 ———活動(dòng) 3兼容(持續(xù)時(shí)間 12-14),加入 S,S={2,8,6,3},t=14所以,問(wèn)題的解為:t=14,S={2,8,6,3}。根據(jù)以上算法編寫(xiě)的程序框架如下:S:={1};j:=1; {遞增序列中的活動(dòng) 1進(jìn)入集合 S,設(shè)定最近進(jìn)入 S的活動(dòng)序號(hào)為 1}for i:=2 to n doif bi’>=ej’ {若遞增序列中的活動(dòng) i與 S集合中的活動(dòng)兼容}then beginS:=S+{i}; {活動(dòng) i進(jìn)入集合 S}t:=ei’; {計(jì)算占用時(shí)間}j:=i; {設(shè)定最近進(jìn)入 S的活動(dòng)序號(hào)為 i}end;輸出占用時(shí)間 t;for i:=1 to n do132if i in S then 輸出活動(dòng) i的序號(hào);小結(jié):一、 貪心算法的基本要素及與動(dòng)態(tài)規(guī)劃算法的關(guān)系對(duì)于一個(gè)具體的問(wèn)題,怎么知道是否可以用貪心算法求解呢?得到的解是不是問(wèn)題的最優(yōu)解呢?這個(gè)問(wèn)題很難給予肯定的回答。但是一般來(lái)說(shuō)這類(lèi)問(wèn)題具有兩個(gè)重要的性質(zhì):1、 貪心選擇性質(zhì):即問(wèn)題的整體最優(yōu)解可以通過(guò)一系列局部最優(yōu)的貪心選擇達(dá)到。這是貪心法可行的第一個(gè)基本要素,也是貪心算法與動(dòng)態(tài)規(guī)劃算法的主要區(qū)別。在動(dòng)態(tài)規(guī)劃算法中,每步所做出的選擇往往依賴(lài)于相關(guān)子問(wèn)題的解。因而只有解出相關(guān)子問(wèn)題后,才能做出選擇。而貪心算法是先做出當(dāng)前的局部最優(yōu)選擇,然后再去解這個(gè)選擇后產(chǎn)生的相應(yīng)子問(wèn)題。所以,貪心算法可以依賴(lài)以往所做的選擇,但決不依賴(lài)將來(lái)所做的選擇,也不依賴(lài)子問(wèn)題的解。對(duì)于一個(gè)具體問(wèn)題,我們一般通過(guò)數(shù)學(xué)歸納法證明他是否具有貪心選擇性質(zhì)。但在實(shí)際比賽中,由于時(shí)間等因素,一般不會(huì)嚴(yán)格地證明,而是要把問(wèn)題的各個(gè)方面、各種情況考慮清楚,多找數(shù)據(jù)測(cè)試和驗(yàn)證。2、 最優(yōu)子結(jié)構(gòu)性質(zhì):當(dāng)一個(gè)問(wèn)題的最優(yōu)解包含其子問(wèn)題的最優(yōu)解時(shí),稱(chēng)此問(wèn)題具有最優(yōu)子結(jié)構(gòu)性質(zhì)。這一性質(zhì)是決定一個(gè)問(wèn)題可否采用貪心或動(dòng)態(tài)規(guī)劃算法的關(guān)鍵特性。比如,在例 4 的活動(dòng)安排中,其最優(yōu)子結(jié)構(gòu)性質(zhì)表現(xiàn)為:若 S 是關(guān)于 E 的活動(dòng)安排問(wèn)題的包含活動(dòng) 1 的一個(gè)最優(yōu)解,則相容活動(dòng)集合 S’=S-{1}是關(guān)于 E’={i 屬于 E : bi>=e1}的活動(dòng)安排問(wèn)題的一個(gè)最優(yōu)解。雖然貪心算法和動(dòng)態(tài)規(guī)劃算法都要求問(wèn)題具有最優(yōu)子結(jié)構(gòu)性質(zhì),但兩者不是通用的。比如前面講到的 0/1 背包問(wèn)題和部分背包問(wèn)題,都具有最優(yōu)子結(jié)構(gòu)性質(zhì),但前者不可以用貪心,而只能用動(dòng)態(tài)規(guī)劃,本質(zhì)原因是:存在空間上的浪費(fèi);而后者是是可以用貪心求的最優(yōu)解。另外,一般而言貪心算法的效率比動(dòng)態(tài)規(guī)劃要高。二、 思考樹(shù)和圖論中的哪些算法是采用的貪心思想。哈夫曼編碼問(wèn)題、Dijkstra 算法求解單源最短路徑問(wèn)題、Prim 算法和 Kruskal 算法求解最小生成樹(shù)問(wèn)題。例 5、雇傭計(jì)劃[問(wèn)題描述] 一位管理項(xiàng)目的經(jīng)理想要確定每個(gè)月需要的工人,他當(dāng)然知道每月所需的最少工人數(shù)。當(dāng)他雇傭或解雇一個(gè)工人時(shí),會(huì)有一些額外支出。一旦一個(gè)工人被雇傭,即使他不工作,他也將得到工資。這位經(jīng)理知道雇傭一個(gè)工人的費(fèi)用,解雇一個(gè)工人的費(fèi)用和一個(gè)工人的工資。現(xiàn)他在考慮一個(gè)問(wèn)題:為了把項(xiàng)目的費(fèi)用控制在最低,他將每月雇傭或解雇多少個(gè)工人。[輸入格式] 輸入文件含有三行。第一行為月數(shù) n(不超過(guò) 12)。第二行含雇傭一個(gè)工人的費(fèi)用,一個(gè)工人的工資和解雇一個(gè)工人的費(fèi)用(≤100)。第三行含 n個(gè)數(shù),分別表示每月最少需要的工人數(shù)(≤1000)。每個(gè)數(shù)據(jù)之間有一個(gè)空格隔開(kāi)。[輸出格式] 輸出僅一行,表示項(xiàng)目的最小總費(fèi)用。[輸入樣例]13334 5 610 9 11[輸出樣例]199[算法分析]我們從第一個(gè)月開(kāi)始,逐月計(jì)算現(xiàn)有工人數(shù),先給這些工人發(fā)放工資。如果雇傭了新工人,則必須給新上崗人員發(fā)放雇傭費(fèi)用;如果削減了部分工人,則必須給下崗人員發(fā)放解雇費(fèi)用。當(dāng)月發(fā)放的工資+雇傭(或解雇)費(fèi)用構(gòu)成了一個(gè)月的總費(fèi)用。我們從第一個(gè)月開(kāi)始,逐月累計(jì)項(xiàng)目總費(fèi)用,直至計(jì)算出 n個(gè)月的總費(fèi)用為止。問(wèn)題是怎樣將這筆費(fèi)用控制在最低?設(shè) mincost 表示最小費(fèi)用和,初始時(shí) mincost=0;now 表示現(xiàn)有工人數(shù),初始時(shí) now=0;min[i]表示第 i個(gè)月所需要的最少工人數(shù)(1≤i≤n);n表示月數(shù);f表示解雇費(fèi)用;s表示工資;h表示雇傭費(fèi)用。則我們需要解決下面的兩個(gè)問(wèn)題:1、怎樣在當(dāng)月工人數(shù)不足的情況下確定雇傭方案如果第 i個(gè)月的所需最少人數(shù) min[i]大于現(xiàn)有工人數(shù) now,則需要雇傭工人。為了盡可能少地減少雇傭費(fèi)用,我們不妨雇傭(min[i]-now)個(gè)工人,使得第 i 個(gè)月的工人數(shù)正好為min[i];如果 min[i]=now,則維持現(xiàn)有工人數(shù) now 不變。算法思想如下:if min[i]>nowthen beginmincost:=mincost+h*(min[i]-now);now:=min[i];end;mincost:=mincost+now*s; { 顯然,這樣的雇傭費(fèi)用支出是最節(jié)約的 }2、怎樣在當(dāng)月工人數(shù)多余的情況下確定解雇方案如果現(xiàn)有工人數(shù) now 大于第 i個(gè)月最少需要的工人數(shù) min[i],則需要解雇一部分工人,最佳方案是否一定是解雇(now-min[i])個(gè)工人呢?不是的。例如對(duì)于示例中的數(shù)據(jù),依上述方法計(jì)算:第 1個(gè)月雇傭 10人:mincost=mincost+h*(min[i]-now)+s*min[i]=0+4*10+5*10=90 now=10第 2個(gè)月解雇 1人,使得現(xiàn)有工人數(shù)為 9人:mincost=mincost+f*(now-min[2])+d*min[2]=90+6*1+9*5=141 now=9第 3個(gè)月雇傭 2人,使得現(xiàn)有工人數(shù)為 11人:mincost=mincost+h*(min[3]-now)+d*min[3]=141+4*2+5*11=204 now=11134顯然,該雇傭計(jì)劃的總費(fèi)用(204)并不是最少的,因?yàn)槿绻?2 個(gè)月不解雇 1 人,仍維持 10人,第 3個(gè)月再雇傭 1人,這種情況下的總費(fèi)用為(4*10+5*10)+(5*10)+(4*1+5*11)=90+50+59=199,即為樣例輸出。由此看出,解雇的人數(shù)應(yīng)比(now-min[i])少一些,那么少多少呢?我們采取這樣的貪心策略去確定:盡可能少地解雇工人,并且在工資支出合理的前提下盡可能使現(xiàn)有工人數(shù)維持在一個(gè)最長(zhǎng)時(shí)間內(nèi),以減少雇傭和解雇的額外支出。實(shí)現(xiàn)的方法是:在 min[i]~min[n]間按最少需要人數(shù)遞增的順序,將月份排成序列 y1 ,y2,……,yn-i,yn-i+1(其中 i≤yj≤n,1≤j≤n-i+1,如圖 1)。從第 yj個(gè)月出發(fā)按照最少需要遞減的順序檢查 min[yj]、min[yj-1],……,一旦發(fā)現(xiàn)第 yj月超員,且這些工人在第 yj+1個(gè)月雇傭與第 i 到第 yj 月期間解雇的總費(fèi)用,比第 i 到第 yj 個(gè)月連續(xù)使用的費(fèi)用節(jié)約,即(min[yj]n))),則在第 i個(gè)月解雇 now-min[yj]個(gè)工人,使現(xiàn)有工人數(shù)變?yōu)?min[yj];否則維持現(xiàn)有工人數(shù)不變。圖 1算法思想如下:在 min[i]~min[n]間按最少需要人數(shù)遞增的順序,將月份排成 y1,……,yn-i+1;for j:=n-i downto 1 doif (min[yj]then beginmincost:=mincost+f*(now-min[yj]);now:=min[yj];andmincost:=mincost+s*now;我們從 i=1 開(kāi)始,依上述辦法逐月累計(jì)費(fèi)用總和,直至 i=n 為止。此時(shí)的費(fèi)用總和最少。例如對(duì)于示例中的數(shù)據(jù),依上述方法計(jì)算:第 1個(gè)月雇傭 10人,費(fèi)用總和為 90;第 2個(gè)月維持現(xiàn)有人數(shù)不變,費(fèi)用總和為 90+5*10=140;第 3個(gè)月雇傭 1人,工人數(shù)增至 11,費(fèi)用總和為 140+5*11-14=199。顯然,這個(gè)答案與樣本輸出一致。結(jié)合上述分析得出本題總的算法框架如下:mincost:=0;now:=0; {初始化}for i:=1 to n dobeginif min[i]>now135then 在現(xiàn)有人數(shù)不足情況下確定第i個(gè)月的雇傭方案并累計(jì)最小費(fèi)用mincost;else 在現(xiàn)有人數(shù)多余情況下確定第i個(gè)月的解雇方案并累計(jì)最小費(fèi)用mincost;end;輸出項(xiàng)目的最小費(fèi)用 mincost;例 6、自動(dòng)柜員機(jī) ATM[問(wèn)題描述]在一個(gè)銀行的大廳里有 100 個(gè)自動(dòng)柜員機(jī),編號(hào)分別為 0..99,每個(gè)會(huì)員顧客都能通過(guò)30這些柜員機(jī)提取<=10 ducats(一種早期的流通硬幣單位)的借款業(yè)務(wù),但必須在一個(gè)星期內(nèi)還是通過(guò)這些柜員機(jī)完成還款業(yè)務(wù)。這種柜員機(jī)很特別,每個(gè)柜員機(jī)只能完成一種簡(jiǎn)單的i動(dòng)作:供客戶(hù)提取固定數(shù)目的現(xiàn)金或接受客戶(hù)固定數(shù)目的還款。第 i 個(gè)柜員機(jī)只能提供 2iducats 的借款業(yè)務(wù),如果 i是偶數(shù)的話(huà);而如果 i是奇數(shù)的話(huà),則第 i個(gè)柜員機(jī)只能提供 2ducats 的還款業(yè)務(wù)。現(xiàn)在,如果有一個(gè)客戶(hù)想要用這些柜員機(jī)借一定數(shù)目的錢(qián),但是每個(gè)柜員機(jī)都只能使用一次,那么,他該使用哪些柜員機(jī)呢?一個(gè)星期內(nèi)還款時(shí),他又該使用哪些柜員機(jī)呢?比如,他要借7 ducats,則他會(huì)從4號(hào)柜員機(jī)拿到16 ducats,從0號(hào)柜員機(jī)拿到1 ducats,再到 3號(hào)柜員機(jī)還掉 8 ducats,到 1號(hào)柜員機(jī)還掉 2 ducats。一個(gè)星期內(nèi)還款時(shí),他會(huì)到 3號(hào)柜員機(jī)先還掉 8 ducats,再到 0號(hào)柜員機(jī)拿到 1 ducats。請(qǐng)你編寫(xiě)一個(gè)程序,當(dāng)一個(gè)客戶(hù)借款,告訴他該使用哪些柜員機(jī),以后還款時(shí)又該使用哪些柜員機(jī)。[輸入]輸入文件 ban.in,第一行為整數(shù) N(N<=1000),表示客戶(hù)的數(shù)目。下面有 N行,每行為30一個(gè)整數(shù),表示每個(gè)客戶(hù)要借多少錢(qián)。注意:每個(gè)客戶(hù)最多能借 10 ducats。[輸出]輸出文件 ban.out,共 2N行,第 2i-1 行表示客戶(hù) i借款時(shí)該使用哪些柜員機(jī),第 2i行表示客戶(hù) i還款時(shí)該使用哪些柜員機(jī)(1<=i<=N),每行都要求按柜員機(jī)編號(hào)從大到小輸出,每個(gè)編號(hào)之間用 1個(gè)空格隔開(kāi)。如果業(yè)務(wù)無(wú)法成交,則輸出 NIE。[樣例]ban.in27633825300114114700748351602698ban.out4 3 1 03 0NIE99 3 1136[問(wèn)題分析] 貪心,時(shí)間和空間復(fù)雜度都是 O(n)。題目中說(shuō)如果 odd(i)則付出,否則得到硬幣,這很容易讓我們想到-2進(jìn)制。例 7、獨(dú)木舟 (KAJ)[問(wèn)題描述]我們計(jì)劃組織一個(gè)獨(dú)木舟旅行。租用的獨(dú)木舟都是一樣的,最多乘兩人,而且載重有一個(gè)限度?,F(xiàn)在要節(jié)約費(fèi)用,所以要盡可能地租用最少的舟。[任務(wù)] 讀入載重量,參加旅行的人數(shù)以及每個(gè)人的體重。計(jì)算所需要租船數(shù)目。[輸入] 文件 KAJ.IN 的第一行是 w, 80<=w<=200,每條船最大的載重量。第二行是整數(shù) n, 1 <= n <= 30000,參加旅行的人數(shù)。接下來(lái)的 n行,每行是一個(gè)整數(shù),范圍[5..w]。表示每個(gè)人的重量。[輸出] 最小租用數(shù)目。[樣例輸入與輸出]KAN.IN:1009902020305060708090KAJ.OUT:6[問(wèn)題分析] 貪心,找到一個(gè)重量最大的,讓它盡可能與重量大的人同乘一船。如此循環(huán)直至所有人都分配完畢。時(shí)間:O(N),空間 O(W)。137回溯法在程序設(shè)優(yōu)解,例題、騎土巡游問(wèn)題、迷宮問(wèn)題、數(shù)的拆分、全排列問(wèn)題、冪集和子集問(wèn)題雖然是按照定的規(guī)則完成一些任務(wù)這些任務(wù)和規(guī)則是無(wú)法用精確的數(shù)學(xué)公式來(lái)描述的不能根據(jù)某種確定的計(jì)算法則去生成解,而是需要采用試探和回溯的搜索策略去求解。因此,回溯法是程序設(shè)計(jì)中解決這類(lèi)問(wèn)題(尤其是遞歸問(wèn)題)的一種重要方法法也稱(chēng)試探法某一種狀態(tài)從這種狀態(tài)出發(fā)所能達(dá)到的所有“狀態(tài)條路走到時(shí)候(不能再前進(jìn)),再倒(或若干步),從另一種可能狀態(tài)出發(fā),繼續(xù)搜索,直的“路徑(狀態(tài))”都試探過(guò)。這種斷“前進(jìn)”、不斷“回溯”尋找解的方法,稱(chēng)作“回溯法”。它的求解過(guò)程實(shí)質(zhì)上是一個(gè)先根遍歷棵“狀態(tài)空間樹(shù)”的過(guò)程,只是這棵樹(shù)不是遍歷前預(yù)先建立的,而是隱含在遍歷探過(guò)程態(tài)和問(wèn)題所求解產(chǎn)生矛盾時(shí),不再繼續(xù)試探解的終結(jié)狀態(tài)。否試探下去便能得到問(wèn)題的角解、一組解或最優(yōu)角這類(lèi)問(wèn)題的程也可以看成是在給定的(或問(wèn)題蘊(yùn)涵根遍歷,并在遍歷過(guò)程中剪去那些不滿(mǎn)足條件的分支的一種搜索算法(深度或?qū)挾?。所以,對(duì)約束條件的分析題求解的一個(gè)關(guān)鍵之處解表示要找一條從A到B的路,我們可以用回溯的思想描述一下求解過(guò)程(不妨借助圖1找一條從A到B的路溯法的一般模式為了應(yīng)用回溯法的解必須能表組(如圖1中的解便求所有的解滿(mǎn)明問(wèn)題,先舉家熟悉的例子皇后問(wèn)題要求在8×8格的國(guó)際象棋上擺放8個(gè)皇后,使其不能互相攻任意兩個(gè)皇后都不處同同一斜線(xiàn)上,輸出一種擺題分析為了解決這個(gè)問(wèn)題,我們把棋盤(pán)的橫坐標(biāo)設(shè)定為i(),縱坐標(biāo)設(shè)定某)時(shí),在這個(gè)位置的垂直方向、水和兩條斜線(xiàn)方向都不能再放后了。圖1便是題解(Q表據(jù)的位置)圖2八皇后問(wèn)題的一個(gè)解然,在每對(duì)每)都有唯一的每行題可以表示成一個(gè)8元組xs),其中x是放置第行)皇后的列坐標(biāo)這個(gè)問(wèn)題的約束條件是:所有的x:都不相同,即所有皇后都保在同一條斜線(xiàn)如圖2的狀態(tài)便滿(mǎn)束條件后問(wèn)題的一個(gè)解,可以表示為以個(gè)貍鯉開(kāi)竄蜜翻圖翻劊鬨眩風(fēng)睏圖3四皇后問(wèn)題的棋盤(pán)狀態(tài)樹(shù)圖3是我們將八皇后問(wèn)題簡(jiǎn)化為四皇后問(wèn)題,它展示了求解過(guò)程中棋盤(pán)狀態(tài)的變化這是一棵四叉樹(shù),樹(shù)上點(diǎn)表示一個(gè)局部布局或整的布局,根結(jié)點(diǎn)表示棋盤(pán)的初始狀態(tài)。每擇的任何時(shí)刻,棋盤(pán)的合法必須滿(mǎn)兩個(gè)棋子都不能占據(jù)棋盤(pán)上的同一行、或者或者同一對(duì)角線(xiàn)。我們發(fā)圖展開(kāi)的分支結(jié)點(diǎn)中除結(jié)結(jié)點(diǎn)都不是合法的布局。因此,求四皇后問(wèn)題的所有合法布過(guò)程,即為在上述約束條件下先根遍狀態(tài)空間樹(shù)的過(guò)述出求后問(wèn)題的回溯算法女八皇后問(wèn)題的遞歸回溯算法貪心算法 在眾多的計(jì)算機(jī)解題策略中,貪心策略可以算得上是最接近人們?nèi)粘K季S的一種解題策略,正基于此,貪心策略在各級(jí)各類(lèi)信息學(xué)競(jìng)賽、尤其在對(duì)NPC類(lèi)問(wèn)題的求解中發(fā)揮著越來(lái)越重要的作用。7.1 貪心策略的定義貪心策略是:指從問(wèn)題的初始狀態(tài)出發(fā),通過(guò)若干次的貪心選擇而得出最優(yōu)值(或較優(yōu)解)的一種解題方法。其實(shí),從“貪心策略”一詞我們便可以看出,貪心策略總是做出在當(dāng)前看來(lái)是最優(yōu)的選擇,也就是說(shuō)貪心策略并不是從整體上加以考慮,它所做出的選擇只是在某種意義上的局部最優(yōu)解,而許多問(wèn)題自身的特性決定了該題運(yùn)用貪心策略可以得到最優(yōu)解或較優(yōu)解。例1:在n行m列的正整數(shù)矩陣中,要求從每一行中選一個(gè)數(shù),使得選出的n個(gè)數(shù)的和最大。本題可用貪心策略:選n次,每一次選相應(yīng)行中的最大值即可。例2:在一個(gè)N×M的方格陣中,每一格子賦予一個(gè)數(shù)(即為權(quán))。規(guī)定每次移動(dòng)時(shí)只能向上或向右?,F(xiàn)試找出一條路徑,使其從左下角至右上角所經(jīng)過(guò)的權(quán)之和最大。本題用貪心策略不能得到最優(yōu)解,我們以2×4的矩陣為例。3 4 61 2 10若按貪心策略求解,所得路徑為:1,3,4,6;若按動(dòng)態(tài)規(guī)劃法求解,所得路徑為:1,2,10,6。例3:設(shè)定有n臺(tái)處理機(jī)p1,p2,......pn,和m個(gè)作業(yè)j1,j2,...jm,處理機(jī)可并行工作,作業(yè)未完成不能中斷,作業(yè)ji在處理機(jī)上的處理時(shí)間為ti,求解最佳方案,使得完成m項(xiàng)工作的時(shí)間最短 本題不能用貪心算法求解:理由是若n=3,m=6 各作業(yè)的時(shí)間分別是11 7 5 5 4 7 用貪心策略解(每次將作業(yè)加到最先空閑的機(jī)器上)time=15,用搜索策略最優(yōu)時(shí)間應(yīng)是14,但是貪心策略給我們提供了一個(gè)線(xiàn)索那就是每臺(tái)處理上的時(shí)間不超過(guò)15,給搜索提供了方便。總之:1. 不能保證求得的最后解是最佳的;2. 只能用來(lái)求某些最大或最小解問(wèn)題;3. 能確定某些問(wèn)題的可行解的范圍,特別是給搜索算法提供了依據(jù)。7. 2 貪心策略的特點(diǎn)貪心算法有什么樣的特點(diǎn)呢?我認(rèn)為,適用于貪心算法解決的問(wèn)題應(yīng)具有以下2個(gè)特點(diǎn):1、貪心選擇性質(zhì):所謂貪心選擇性質(zhì)是指應(yīng)用同一規(guī)則f,將原問(wèn)題變?yōu)橐粋€(gè)相似的、但規(guī)模更小的子問(wèn)題、而后的每一步都是當(dāng)前看似最佳的選擇。這種選擇依賴(lài)于已做出的選擇,但不依賴(lài)于未做出的選擇。從全局來(lái)看,運(yùn)用貪心策略解決的問(wèn)題在程序的運(yùn)行過(guò)程中無(wú)回溯過(guò)程。關(guān)于貪心選擇性質(zhì),讀者可在后文給出的貪心策略狀態(tài)空間圖中得到深刻地體會(huì)。2、局部最優(yōu)解:我們通過(guò)特點(diǎn)2向大家介紹了貪心策略的數(shù)學(xué)描述。由于運(yùn)用貪心策略解題在每一次都取得了最優(yōu)解,但能夠保證局部最優(yōu)解得不一定是貪心算法。如大家所熟悉得動(dòng)態(tài)規(guī)劃算法就可以滿(mǎn)足局部最優(yōu)解,但貪心策略比動(dòng)態(tài)規(guī)劃時(shí)間效率更高站用內(nèi)存更少,編寫(xiě)程序更簡(jiǎn)單。7.3 典型例題與習(xí)題 例4:背包問(wèn)題:有一個(gè)背包,背包容量是M=150。有7個(gè)物品,物品可以分割成任意大小。要求盡可能讓裝入背包中的物品總價(jià)值最大,但不能超過(guò)總?cè)萘俊?br/>物品 A B C D E F G重量 35 30 60 50 40 10 25價(jià)值 10 40 30 50 35 40 30 分析:目標(biāo)函數(shù): ∑pi最大約束條件是裝入的物品總重量不超過(guò)背包容量:∑wi<=M( M=150)(1)根據(jù)貪心的策略,每次挑選價(jià)值最大的物品裝入背包,得到的結(jié)果是否最優(yōu)?(2)每次挑選所占空間最小的物品裝入是否能得到最優(yōu)解?(3)每次選取單位容量?jī)r(jià)值最大的物品,成為解本題的策略。程序如下:program beibao;const m=150; n=7;var xu:integer; i,j:integer; goods:array[1..n,0..2] of integer; ok:array[1..n,1..2] of real;procedure init; var i:integer; begin xu:=m; for i:=1 to n do begin write('Enter the price and weight of the ',i,'th goods:'); goods[i,0]:=i; read(goods[i,1],goods[i,2]); readln; ok[i,1]:=0; ok[i,2]:=0; end; end;procedure make; var bi:array[1..n] of real; i,j:integer; temp1,temp2,temp0:integer; begin for i:=1 to n do bi[i]:=goods[i,1]/goods[i,2]; for i:=1 to n-1 do for j:=i+1 to n do begin if bi[i] temp0:=goods[i,0]; temp1:=goods[i,1]; temp2:=goods[i,2]; goods[i,0]:=goods[j,0]; goods[i,1]:=goods[j,1]; goods[i,2]:=goods[j,2]; goods[j,0]:=temp0; goods[j,1]:=temp1; goods[j,2]:=temp2; end; end; end;begin init; make; for i:=1 to 7 do begin if goods[i,2]>xu then break; ok[i,1]:=goods[i,0]; ok[i,2]:=1; xu:=xu-goods[i,2]; end; j:=i; if i<=n then begin ok[i,1]:=goods[i,0]; ok[i,2]:=xu/goods[i,2]; end; for i:=1 to j do writeln(ok[i,1]:1:0,':',ok[i,2]*goods[i,2]:2:1);end.例5:旅行家的預(yù)算問(wèn)題:一個(gè)旅行家想駕駛汽車(chē)以最少的費(fèi)用從一個(gè)城市到另一個(gè)城市,給定兩個(gè)城市間的距離d1,汽車(chē)油箱的容量是c,每升汽油能行駛的距離d2,出發(fā)時(shí)每升汽油的價(jià)格是p,沿途加油站數(shù)為n(可為0),油站i離出發(fā)點(diǎn)的距離是di,每升汽油的價(jià)格是pi。計(jì)算結(jié)果四舍五入保留小數(shù)點(diǎn)后兩位,若無(wú)法到達(dá)目的地輸出“No answer" 若輸入:d1=275.6 c=11.9 d2=27.4 p=8 n=2d[1]=102 p[1]=2.9d[2]=220 p[2]=2.2output26.95本問(wèn)題的貪心策略是:找下一個(gè)較便宜的油站,根據(jù)距離確定加滿(mǎn)、不加、加到剛好到該站。程序如下:program jiayou;const maxn=10001;zero=1e-16;type jd=record value,way,over:real; end;var oil:array[1..maxn] of ^jd; n:integer; d1,c,d2,cost,maxway:real;function init:boolean;var i:integer;begin new(oil[1]); oil[1]^.way:=0; read(d1,c,d2,oil[1]^.value,n); maxway:=d2*c; for i:=2 to n+1 do begin new(oil[i]); readln(oil[i]^.way,oil[i]^.value); oil[i]^.over:=0; end; inc(n,2); new(oil[n]); oil[n]^.way:=d1; oil[n]^.value:=0; oil[n]^.over:=0; for i:=2 to n do if oil[i]^.way-oil[i-1]^.way>maxway then begin init:=false; exit end;init:=true;end;procedure buy(i:integer;miles:real);begin cost:=cost+miles/d2*oil[i]^.value;end;procedure solve;var i,j:integer; s:real;begin i:=1;j:=i+1; repeat s:=0.0; while( s<=maxway+zero) and (j<=n-1) and (oil[i]^.value<=oil[j]^.value) do begin inc(j); s:=s+oil[j]^.way-oil[j-1]^.way end; if s<=maxway+zero then if (oil[i]^.over+zero>=oil[j]^.way-oil[i]^.way) then oil[j]^.over:=oil[i]^.over-(oil[j]^.way-oil[i]^.way) else begin buy(i,oil[j]^.way-oil[i]^.way-oil[i]^.over); oil[j]^.over:=0.0; end else begin buy(i,maxway-oil[i]^.over); j:=i+1; oil[j]^.over:=maxway-(oil[j]^.way-oil[i]^.way); end; i:=j; until i=n; end;begin cost:=0; if init then begin solve; writeln(cost:0:2); end else writeln('No answer');end.例6:n個(gè)部件,每個(gè)部件必須經(jīng)過(guò)先A后B兩道工序。 以知部件i在A,B 機(jī)器上的時(shí)間分別為ai,bi。如何安排加工順序,總加工時(shí)間最短?輸入:5部件 1 2 3 4 5ai 3 5 8 7 10bi 6 2 1 4 9輸出:341 5 4 2 3本問(wèn)題的貪心策略是A機(jī)器上加工短的應(yīng)優(yōu)先,B機(jī)器上加工短的應(yīng)靠后。程序如下:program workorder;const maxn=100;type jd=record a,b,m,o:integer; end;var n,min,i:integer; c:array[1..maxn] of jd; order:array[1..maxn] of integer;procedure init;var i:integer;begin readln(n); for i:=1 to n do read(c[i].a); readln; for i:=1 to n do read(c[i].b); readln; for i:=1 to n do begin if c[i].a c[i].o:=i; end;end;procedure sort;var i,j,k,t:integer; temp:jd;begin for i:=1 to n-1 do begin k:=i;t:=c[i].m; for j:=i+1 to n do if c[j].m if k<>i then begin temp:=c[i];c[i]:=c[k];c[k]:=temp end end;end;procedure playorder;var i,s,t:integer;begin fillchar(order,sizeof(order),0); s:=1; t:=n; for i:=1 to n do if c[i].m=c[i].a then begin order[s]:=i;s:=s+1 end else begin order[t]:=i;t:=t-1;end;end;procedure calc_t;var i,t1,t2:integer;begin t1:=0;t2:=0; for i:=1 to n do begin t1:=t1+c[order[i]].a; if t2 t2:=t2+c[order[i]].b; end;min:=t2;end;begin init; sort; playorder; calc_t; writeln(min); for i:=1 to n do write(c[order[i]].o,' '); writeln;end.習(xí)題:1.最佳瀏覽路線(xiàn)問(wèn)題:某旅游區(qū)的街道成網(wǎng)格狀(見(jiàn)圖),其中東西向的街道都是旅游街,南北向的街道都是林蔭道。由于游客眾多,旅游街被規(guī)定為單行道。游客在旅游街上只能從西向東走,在林蔭道上既可以由南向北走,也可以從北向南走。阿隆想到這個(gè)旅游區(qū)游玩。他的好友阿福給了他一些建議,用分值表示所有旅游街相鄰兩個(gè)路口之間的道路值得瀏覽得程度,分值從-100到100的整數(shù),所有林蔭道不打分。所有分值不可能全是負(fù)值。 例如下圖是被打過(guò)分的某旅游區(qū)的街道圖: 圖6阿隆可以從任一路口開(kāi)始瀏覽,在任一路口結(jié)束瀏覽。請(qǐng)你寫(xiě)一個(gè)程序,幫助阿隆尋找一條最佳的瀏覽路線(xiàn),使得這條路線(xiàn)的所有分值總和最大。2..刪數(shù)問(wèn)題鍵盤(pán)輸入一個(gè)高精度的正整數(shù)N,去掉其中任意S個(gè)數(shù)字后剩下的數(shù)字按左右次序組成一個(gè)新的正整數(shù)。對(duì)給定的N和S,尋找一種刪數(shù)規(guī)則使得剩下得數(shù)字組成的新數(shù)最小。動(dòng)態(tài)規(guī)劃初步動(dòng)態(tài)規(guī)劃簡(jiǎn)介動(dòng)態(tài)規(guī)劃是運(yùn)籌學(xué)的一個(gè)分支決多階段決策過(guò)程最優(yōu)化問(wèn)題的一種方法。195年,美國(guó)數(shù)學(xué)家解決這類(lèi)問(wèn)題的“最優(yōu)化原則年發(fā)表的名著《動(dòng)態(tài)規(guī)劃》,該書(shū)是動(dòng)態(tài)規(guī)劃方面的第一本著作。動(dòng)態(tài)規(guī)劃問(wèn)世以來(lái),在工農(nóng)業(yè)生程技術(shù)等許多方面都得到應(yīng)用,取得的效動(dòng)態(tài)規(guī)劃息學(xué)競(jìng)賽是在90年代初期,它以獨(dú)特的優(yōu)點(diǎn)獲題者的青睞它就成為了信息學(xué)競(jìng)賽中必不可少方法所有的國(guó)內(nèi)和國(guó)際信競(jìng)賽至少有一道動(dòng)態(tài)規(guī)劃動(dòng)態(tài)規(guī)劃常重要面,我們先通過(guò)兩個(gè)具體問(wèn)題認(rèn)例1、攔截導(dǎo)彈(NOIP1999題描述某國(guó)為了防御敵彈襲擊,發(fā)展出一種導(dǎo)彈攔截系統(tǒng)。但是這種導(dǎo)彈攔截系統(tǒng)有缺陷:雖然它的第一發(fā)炮彈能任意的高度,但是以后每一發(fā)炮彈都不能高于前一發(fā)度雷達(dá)捕捉到敵國(guó)的導(dǎo)彈來(lái)襲統(tǒng)還在試用階段,所以統(tǒng)因此有可能不能攔截所有的導(dǎo)入導(dǎo)彈的高度數(shù)據(jù)是不0000的正整數(shù),每個(gè)數(shù)至空格),計(jì)算這套系統(tǒng)最多能攔截多少導(dǎo)彈,如果要攔截所有導(dǎo)彈最少要配備多少套這種導(dǎo)彈攔截系統(tǒng)輸入輸出樣例006(最多能攔截的導(dǎo)彈數(shù)要攔截所有導(dǎo)彈最少要配備的系統(tǒng)數(shù)問(wèn)題分析我們先解決第系統(tǒng)最多能攔多少導(dǎo)彈,跟它最后攔截的導(dǎo)彈高度有很大關(guān)系假設(shè)枚導(dǎo)彈是第i枚時(shí),系統(tǒng)能攔得的最大導(dǎo)彈數(shù)。例如,樣果系統(tǒng)攔截的最后一枚299的話(huà),最多可以攔截第1枚(389)、第枚(300)、第5枚(299)三枚最大值就是第一問(wèn)的答案。關(guān)鍵是怎樣求得a假設(shè)現(xiàn)在已經(jīng)求得a[1]a線(xiàn)街校圳的批位味數(shù)的2系統(tǒng)攔截攔截的導(dǎo)彈高度必假如最后第二枚假如倒數(shù)第彈是299類(lèi)似地當(dāng)然,我們現(xiàn)在求得是以65結(jié)尾的最彈數(shù)因此取所有的最類(lèi)似地,我們可以假設(shè)a[1]a[6]為已知,來(lái)求得a樣,a[6]、a[5]、a[4]、a2]也是類(lèi)似求法就即如果系統(tǒng)攔截的最后1枚389,則只能攔截第這樣,求解過(guò)程可以用下列式子歸納最后,只需把的最大值輸這就是第一問(wèn)的解法,這種解題方法就稱(chēng)為“動(dòng)態(tài)規(guī)劃第二問(wèn)比較有意緊接著第所以很容易受前面的影響,多次采用第的辦法,然后數(shù),其實(shí)這是不對(duì)的。要舉反為7的高度序不上升序列為多次求最長(zhǎng)不上升序列的結(jié)果系其實(shí)分別擊落所以不能用“動(dòng)態(tài)規(guī)劃”做,那的做法又是什么呢我們的目標(biāo)是用最統(tǒng)擊落所有導(dǎo)彈系統(tǒng)之間怎么分配導(dǎo)彈數(shù)目則無(wú)關(guān)緊面錯(cuò)誤的想法正是承襲套系統(tǒng)盡量多攔截導(dǎo)思維定勢(shì),忽視了最優(yōu)解系統(tǒng)攔截?cái)?shù)較為平均的本質(zhì)上是一種貪心算法,但貪心的策略不對(duì)。如果從每套系統(tǒng)攔截的導(dǎo)彈方面來(lái)想行我們就應(yīng)該換一個(gè)思路,從攔截某個(gè)導(dǎo)彈所選的系統(tǒng)題我有系統(tǒng)瞄準(zhǔn)高度必須犯導(dǎo)彈高度,所統(tǒng)均無(wú)法攔截就不得不啟用新系統(tǒng)。如果已有系統(tǒng)中有攔截該導(dǎo)彈,我是應(yīng)該繼續(xù)使用是另起爐灶呢 事實(shí)是:無(wú)論用哪套系統(tǒng)截了這枚導(dǎo)彈,那系統(tǒng)的瞄準(zhǔn)高度就等度,這一點(diǎn)對(duì)舊的或新的系統(tǒng)都適用。而新系統(tǒng)能攔截彈髙度最高,即新系統(tǒng)的性能優(yōu)于任意一套已使用的系統(tǒng)。既然如此,我們當(dāng)然應(yīng)該選擇有的系統(tǒng)。如果統(tǒng)中有多攔截隹高度較高的系統(tǒng)的“潛力”較較低的系統(tǒng)則不同打下的導(dǎo)彈別的系統(tǒng)也能打下到的導(dǎo)彈卻未必是統(tǒng)所夠不到的。所以,當(dāng)有多個(gè)系統(tǒng)供選擇時(shí),要選瞄準(zhǔn)高度最低的使用,當(dāng)然瞄準(zhǔn)高度同時(shí)也要」下當(dāng)前已有系統(tǒng)的各個(gè)當(dāng)前瞄準(zhǔn)高度,該數(shù)組中實(shí)際元素數(shù)就是第二問(wèn)的解答[參考程序ength(line)do(分解current:=0;(彈的高度134 展開(kāi)更多...... 收起↑ 資源列表 第20講 回溯法.pdf 第23講 貪心法.pdf 第25講 動(dòng)態(tài)規(guī)劃.pdf 貪心算法.doc 縮略圖、資源來(lái)源于二一教育資源庫(kù)