01背包

轉(zhuǎn)自背包九問(wèn):http://love-oriented.com/pack/P01.html

P01: 01背包問(wèn)題

題目

有N件物品和一個(gè)容量為V的背包菱阵。第i件物品的費(fèi)用是c[i]微驶,價(jià)值是w[i]。求解將哪些物品裝入背包可使價(jià)值總和最大呼巷。

基本思路

這是最基礎(chǔ)的背包問(wèn)題,特點(diǎn)是:每種物品僅有一件,可以選擇放或不放蹦哼。
用子問(wèn)題定義狀態(tài):即f[i][v]表示前i件物品恰放入一個(gè)容量為v的背包可以獲得的最大價(jià)值。則其狀態(tài)轉(zhuǎn)移方程便是:

f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

這個(gè)方程非常重要要糊,基本上所有跟背包相關(guān)的問(wèn)題的方程都是由它衍生出來(lái)的纲熏。所以有必要將它詳細(xì)解釋一下:“將前i件物品放入容量為v的背包中”這個(gè)子問(wèn)題,若只考慮第i件物品的策略(放或不放)锄俄,那么就可以轉(zhuǎn)化為一個(gè)只牽扯前i-1件物品的問(wèn)題局劲。如果不放第i件物品,那么問(wèn)題就轉(zhuǎn)化為“前i-1件物品放入容量為v的背包中”奶赠,價(jià)值為f[i-1][v]鱼填;如果放第i件物品,那么問(wèn)題就轉(zhuǎn)化為“前i-1件物品放入剩下的容量為v-c[i]的背包中”车柠,此時(shí)能獲得的最大價(jià)值就是f[i-1][v-c[i]]再加上通過(guò)放入第i件物品獲得的價(jià)值w[i]剔氏。

優(yōu)化空間復(fù)雜度

以上方法的時(shí)間和空間復(fù)雜度均為O(VN),其中時(shí)間復(fù)雜度應(yīng)該已經(jīng)不能再優(yōu)化了竹祷,但空間復(fù)雜度卻可以優(yōu)化到O(N)谈跛。
先考慮上面講的基本思路如何實(shí)現(xiàn),肯定是有一個(gè)主循環(huán)i=1..N塑陵,每次算出來(lái)二維數(shù)組f[i][0..V]的所有值感憾。那么,如果只用一個(gè)數(shù)組f[0..V]令花,能不能保證第i次循環(huán)結(jié)束后f[v]中表示的就是我們定義的狀態(tài)f[i][v]呢阻桅?f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]兩個(gè)子問(wèn)題遞推而來(lái),能否保證在推f[i][v]時(shí)(也即在第i次主循環(huán)中推f[v]時(shí))能夠得到f[i-1][v]和f[i-1][v-c[i]]的值呢兼都?事實(shí)上嫂沉,這要求在每次主循環(huán)中我們以v=V..0的順序推f[v],這樣才能保證推f[v]時(shí)f[v-c[i]]保存的是狀態(tài)f[i-1][v-c[i]]的值扮碧。偽代碼如下:

for i=1..N
     for v=V..0
         f[v]=max{f[v],f[v-c[i]]+w[i]};

其中的f[v]=max{f[v],f[v-c[i]]}一句恰就相當(dāng)于我們的轉(zhuǎn)移方程f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]}
趟章,因?yàn)楝F(xiàn)在的f[v-c[i]]就相當(dāng)于原來(lái)的f[i-1][v-c[i]]杏糙。
如果將v的循環(huán)順序從上面的逆序改成順序的話,那么則成了f[i][v]由f[i][v-c[i]]推知蚓土,與本題意不符宏侍,但它卻是另一個(gè)重要的背包問(wèn)題P02最簡(jiǎn)捷的解決方案,故學(xué)習(xí)只用一維數(shù)組解01背包問(wèn)題是十分必要的蜀漆。
事實(shí)上谅河,使用一維數(shù)組解01背包的程序在后面會(huì)被多次用到,所以這里抽象出一個(gè)處理一件01背包中的物品過(guò)程确丢,以后的代碼中直接調(diào)用不加說(shuō)明绷耍。
過(guò)程ZeroOnePack,表示處理一件01背包中的物品蠕嫁,兩個(gè)參數(shù)cost锨天、weight分別表明這件物品的費(fèi)用和價(jià)值。

procedure ZeroOnePack(cost,weight)
           for v=V..cost
                 f[v]=max{f[v],f[v-cost]+weight}

注意這個(gè)過(guò)程里的處理與前面給出的偽代碼有所不同剃毒。前面的示例程序?qū)懗蓈=V..0是為了在程序中體現(xiàn)每個(gè)狀態(tài)都按照方程求解了,避免不必要的思維復(fù)雜度搂赋。而這里既然已經(jīng)抽象成看作黑箱的過(guò)程了赘阀,就可以加入優(yōu)化。費(fèi)用為cost的物品不會(huì)影響狀態(tài)f[0..cost-1]脑奠,這是顯然的基公。
有了這個(gè)過(guò)程以后,01背包問(wèn)題的偽代碼就可以這樣寫(xiě):

      for i=1..N 
            ZeroOnePack(c[i],w[i]);

初始化的細(xì)節(jié)問(wèn)題

我們看到的求最優(yōu)解的背包問(wèn)題題目中宋欺,事實(shí)上有兩種不太相同的問(wèn)法轰豆。有的題目要求“恰好裝滿背包”時(shí)的最優(yōu)解,有的題目則并沒(méi)有要求必須把背包裝滿齿诞。一種區(qū)別這兩種問(wèn)法的實(shí)現(xiàn)方法是在初始化的時(shí)候有所不同酸休。
如果是第一種問(wèn)法,要求恰好裝滿背包祷杈,那么在初始化時(shí)除了f[0]為0其它f[1..V]均設(shè)為-∞斑司,這樣就可以保證最終得到的f[N]是一種恰好裝滿背包的最優(yōu)解。
如果并沒(méi)有要求必須把背包裝滿但汞,而是只希望價(jià)格盡量大宿刮,初始化時(shí)應(yīng)該將f[0..V]全部設(shè)為0。
為什么呢私蕾?可以這樣理解:初始化的f數(shù)組事實(shí)上就是在沒(méi)有任何物品可以放入背包時(shí)的合法狀態(tài)僵缺。如果要求背包恰好裝滿,那么此時(shí)只有容量為0的背包可能被價(jià)值為0的nothing“恰好裝滿”踩叭,其它容量的背包均沒(méi)有合法的解磕潮,屬于未定義的狀態(tài),它們的值就都應(yīng)該是-∞了。如果背包并非必須被裝滿揉抵,那么任何容量的背包都有一個(gè)合法解“什么都不裝”亡容,這個(gè)解的價(jià)值為0,所以初始時(shí)狀態(tài)的值也就全部為0了冤今。
這個(gè)小技巧完全可以推廣到其它類(lèi)型的背包問(wèn)題闺兢,后面也就不再對(duì)進(jìn)行狀態(tài)轉(zhuǎn)移之前的初始化進(jìn)行講解。

一個(gè)常數(shù)優(yōu)化

前面的偽代碼中有 for v=V..1戏罢,可以將這個(gè)循環(huán)的下限進(jìn)行改進(jìn)屋谭。
由于只需要最后f[v]的值,倒推前一個(gè)物品龟糕,其實(shí)只要知道f[v-w[n]]即可桐磁。以此類(lèi)推,對(duì)以第j個(gè)背包讲岁,其實(shí)只需要知道到f[v-sum{w[j..n]}]即可我擂,即代碼中的

for i=1..N for v=V..0

可以改成

for i=1..n 
  bound=max{V-sum{w[i..n]},c[i]} 
    for v=V..bound

這對(duì)于V比較大時(shí)是有用的。

小結(jié)

01背包問(wèn)題是最基本的背包問(wèn)題缓艳,它包含了背包問(wèn)題中設(shè)計(jì)狀態(tài)校摩、方程的最基本思想,另外阶淘,別的類(lèi)型的背包問(wèn)題往往也可以轉(zhuǎn)換成01背包問(wèn)題求解衙吩。故一定要仔細(xì)體會(huì)上面基本思路的得出方法,狀態(tài)轉(zhuǎn)移方程的意義溪窒,以及最后怎樣優(yōu)化的空間復(fù)雜度坤塞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市澈蚌,隨后出現(xiàn)的幾起案子摹芙,更是在濱河造成了極大的恐慌,老刑警劉巖惜浅,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瘫辩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡坛悉,警方通過(guò)查閱死者的電腦和手機(jī)伐厌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)裸影,“玉大人挣轨,你說(shuō)我怎么就攤上這事⌒桑” “怎么了卷扮?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵荡澎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我晤锹,道長(zhǎng)摩幔,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任鞭铆,我火速辦了婚禮或衡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘车遂。我一直安慰自己封断,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布舶担。 她就那樣靜靜地躺著坡疼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪衣陶。 梳的紋絲不亂的頭發(fā)上柄瑰,一...
    開(kāi)封第一講書(shū)人閱讀 51,258評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音祖搓,去河邊找鬼狱意。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拯欧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播财骨,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼镐作,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了隆箩?” 一聲冷哼從身側(cè)響起该贾,我...
    開(kāi)封第一講書(shū)人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捌臊,沒(méi)想到半個(gè)月后杨蛋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡理澎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年逞力,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糠爬。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寇荧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出执隧,到底是詐尸還是另有隱情揩抡,我是刑警寧澤户侥,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站峦嗤,受9級(jí)特大地震影響蕊唐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜烁设,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一替梨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧署尤,春花似錦耙替、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至箕别,卻和暖如春铜幽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背串稀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工除抛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人母截。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓到忽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親清寇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子喘漏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容