wikioi天梯之1014 裝箱問題 入門動態規劃 【揹包問題】
動態規劃一直不是很清楚 上網搜了一下 又見識了一個牛人 dd_engi寫的揹包九講
把他的 01揹包問題 直接貼過來了
01揹包問題
題目
有N件物品和一個容量為V的揹包。第i件物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使價值總和最大。
基本思路
這是最基礎的揹包問題,特點是:每種物品僅有一件,可以選擇放或不放。
用子問題定義狀態:即f[i][v]表示前i件物品恰放入一個容量為v的揹包可以獲得的最大價值。則其狀態轉移方程便是:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
這個方程非常重要,基本上所有跟揹包相關的問題的方程都是由它衍生出來的。所以有必要將它詳細解釋一下:“將前i件物品放入容量為v的揹包中”這個子問題,若只考慮第i件物品的策略(放或不放),那麼就可以轉化為一個只牽扯前i-1件物品的問題。如果不放第i件物品,那麼問題就轉化為“前i-1件物品放入容量為v的揹包中”,價值為f[i-1][v];如果放第i件物品,那麼問題就轉化為“前i-1件物品放入剩下的容量為v-c[i]的揹包中”,此時能獲得的最大價值就是f[i-1][v-c[i]]再加上通過放入第i件物品獲得的價值w[i]。
優化空間複雜度
以上方法的時間和空間複雜度均為O(VN),其中時間複雜度應該已經不能再優化了,但空間複雜度卻可以優化到O。
先考慮上面講的基本思路如何實現,肯定是有一個主迴圈i=1..N,每次算出來二維陣列f[i][0..V]的所有值。那麼,如果只用一個數組f[0..V],能不能保證第i次迴圈結束後f[v]中表示的就是我們定義的狀態f[i][v]呢?f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]兩個子問題遞推而來,能否保證在推f[i][v]時(也即在第i次主迴圈中推f[v]時)能夠得到f[i-1][v]和f[i-1][v-c[i]]的值呢?事實上,這要求在每次主迴圈中我們以v=V..0的順序推f[v],這樣才能保證推f[v]時f[v-c[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]]}一句恰就相當於我們的轉移方程f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]}
,因為現在的f[v-c[i]]就相當於原來的f[i-1][v-c[i]]。如果將v的迴圈順序從上面的逆序改成順序的話,那麼則成了f[i][v]由f[i][v-c[i]]推知,與本題意不符,但它卻是另一個重要的揹包問題P02最簡捷的解決方案,故學習只用一維陣列解01揹包問題是十分必要的。
事實上,使用一維陣列解01揹包的程式在後面會被多次用到,所以這裡抽象出一個處理一件01揹包中的物品過程,以後的程式碼中直接呼叫不加說明。
過程ZeroOnePack,表示處理一件01揹包中的物品,兩個引數cost、weight分別表明這件物品的費用和價值。
procedure ZeroOnePack(cost,weight) for v=V..cost f[v]=max{f[v],f[v-cost]+weight}
注意這個過程裡的處理與前面給出的虛擬碼有所不同。前面的示例程式寫成v=V..0是為了在程式中體現每個狀態都按照方程求解了,避免不必要的思維複雜度。而這裡既然已經抽象成看作黑箱的過程了,就可以加入優化。費用為cost的物品不會影響狀態f[0..cost-1],這是顯然的。
有了這個過程以後,01揹包問題的虛擬碼就可以這樣寫:
for i=1..N ZeroOnePack(c[i],w[i]);
初始化的細節問題
我們看到的求最優解的揹包問題題目中,事實上有兩種不太相同的問法。有的題目要求“恰好裝滿揹包”時的最優解,有的題目則並沒有要求必須把揹包裝滿。一種區別這兩種問法的實現方法是在初始化的時候有所不同。
如果是第一種問法,要求恰好裝滿揹包,那麼在初始化時除了f[0]為0其它f[1..V]均設為-∞,這樣就可以保證最終得到的f[N]是一種恰好裝滿揹包的最優解。
如果並沒有要求必須把揹包裝滿,而是隻希望價格儘量大,初始化時應該將f[0..V]全部設為0。
為什麼呢?可以這樣理解:初始化的f陣列事實上就是在沒有任何物品可以放入揹包時的合法狀態。如果要求揹包恰好裝滿,那麼此時只有容量為0的揹包可能被價值為0的nothing“恰好裝滿”,其它容量的揹包均沒有合法的解,屬於未定義的狀態,它們的值就都應該是-∞了。如果揹包並非必須被裝滿,那麼任何容量的揹包都有一個合法解“什麼都不裝”,這個解的價值為0,所以初始時狀態的值也就全部為0了。
這個小技巧完全可以推廣到其它型別的揹包問題,後面也就不再對進行狀態轉移之前的初始化進行講解。
一個常數優化
前面的虛擬碼中有 for v=V..1,可以將這個迴圈的下限進行改進。
由於只需要最後f[v]的值,倒推前一個物品,其實只要知道f[v-w[n]]即可。以此類推,對以第j個揹包,其實只需要知道到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
這對於V比較大時是有用的。
小結
01揹包問題是最基本的揹包問題,它包含了揹包問題中設計狀態、方程的最基本思想,另外,別的型別的揹包問題往往也可以轉換成01揹包問題求解。故一定要仔細體會上面基本思路的得出方法,狀態轉移方程的意義,以及最後怎樣優化的空間複雜度。
按照上面的講解可以把這題過了。。
另外還有一個部落格仔細分析了一下這個揹包九講 可以參考一下
這個部落格分析的也可以
#include <iostream>
#include <cstring>
using namespace std;
int max(const int & a,const int & b){return a > b ? a : b;}
void ZeroOnePack(const int & cost,const int & value,int * f,const int & total)
{
for(int i = total;i >= cost;i--)
{
f[i] = max(f[i],f[i - cost] + value);
}
}
int main()
{
int v,n;
int f[20001];
int a;
cin>>v>>n;
memset(f,0,sizeof(f));
// cout<<sizeof(f)/sizeof(int)<<endl;//測試一下memset的清零情況。。無關緊要
// for(unsigned i = 0;i < 20001;i++)
// cout<<f[i]<<" ";
for(int i = 0;i < n;i++)
{
cin>>a;
if(a <= v)//是否能一次放入
{
ZeroOnePack(a,a,f,v);
}
}
cout<<v -f[v]<<endl;
return 0;
}
關於大牛dd_engi的資料 搜尋了一下 真是不簡單!
相關推薦
wikioi天梯之1014 裝箱問題 入門動態規劃 【揹包問題】
題目 動態規劃一直不是很清楚 上網搜了一下 又見識了一個牛人 dd_engi寫的揹包九講 把他的 01揹包問題 直接貼過來了 01揹包問題 題目 有N件物品和一個容量為V的揹包。第i件物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使價值總和最大。
入門動態規劃 洛谷P1108 低價購買
i++ 一支 股票 algorithm namespace 整數 變形 價格 div P1108 低價購買 題目描述 “低價購買”這條建議是在奶牛股票市場取得成功的一半規則。要想被認為是偉大的投資者,你必須遵循以下的問題建議:“低價購買;再低價購買”。每次你購買一支股票,你
演算法入門——動態規劃
用淺顯的話說動態規劃就是必須一環扣一環得去處理事務,如果有其中一環丟失了,那麼後續就會處理失敗了:比如皇帝要給所有的百姓免稅,並且要根據各個地方的政策免去不同數額的稅率。但是當時並不是網際網路時代,皇帝的聲音並不能響徹全國,也無法計算出各地的稅率。但又必須要讓全國人民知道。這時候就需要用到這個演
藍橋杯-裝箱問題-動態規劃-java
問題描述 有一個箱子容量為V(正整數,0<=V<=20000),同時有n個物品(0<n<=30),每個物品有一個體積(正整數)。 要求n個物品中,任取若干個裝入箱內,使箱子的剩餘空間為最小。 輸入格式 第一行為一個整數,表示箱子容量; 第二行為一個整數
裝箱問題---動態規劃
問題描述 有一個箱子容量為V(正整數,0<=V<=20000),同時有n個物品(0<n<=30),每個物品有一個體積(正整數)。 要求n個物品中,任取若干個裝入箱內,使箱子的剩餘空間為最小。輸入格式 第一行為一個整數,表示箱子容量; 第二行為一個整數,表示有n個物品;
MIT演算法導論公開課之第15課 動態規劃、最長公共子序列
動態規劃(Dynamic programming) 動態規劃是一種設計技巧,而不是一種特定的演算法,就像分治法一樣。 最長公共子序列(Longest common subsequence)問題 有兩個序列,序列x[1~m],序列y[1~n],找到它們的最長
wikioi天梯之3118 高精度練習之除法
題目 做了天梯的加減乘然後又把除法找出來做了下 利用減法做除法 所以先要保證減法寫的是對的 這次直接寫減法 比上次速度提高了 而且竟然一次寫對了。 之前做過加減乘除 除法就沒有參考資料了 自己獨立寫的 最終也寫出來了。 #include <iostream>
演算法題之動態規劃-01揹包問題
文字介紹解決揹包問題 假設山洞裡共有a,b,c,d ,e這5件寶物(不是5種寶物),它們的重量分別是2,2,6,5,4,它們的價值分別是6,3,5,4,6,現在給你個承重為10的揹包, 怎麼裝揹包,可以才能帶走最多的財富。 此時只要理解了狀態轉換方程f[i,j] = Max{ f[i-1,j-Wi]+Pi(
【洛谷】【動態規劃/背包】P1833 櫻花
ios clas 但是 輸入 ostream 代碼 iostream pan time 【題目描述:】 愛與愁大神後院裏種了n棵櫻花樹,每棵都有美學值Ci。愛與愁大神在每天上學前都會來賞花。愛與愁大神可是生物學霸,他懂得如何欣賞櫻花:一種櫻花樹看一遍過,一種櫻花樹最多看A
【洛谷】【動態規劃(二維)】P1508 Likecloud-吃、吃、吃
方程 con == dash fine 自己 pan ans amp 【題目描述:】 正處在某一特定時期之中的李大水牛由於消化系統比較發達,最近一直處在饑餓的狀態中。某日上課,正當他餓得頭昏眼花之時,眼前突然閃現出了一個n*m(n and m<=200)的矩型的巨型
【洛谷】【動態規劃(多維)】P1006 傳紙條
朋友 namespace PE n) 原來 這樣的 max 沒有 空間 【題目描述:】 小淵和小軒是好朋友也是同班同學,他們在一起總有談不完的話題。一次素質拓展活動中,班上同學安排做成一個m行n列的矩陣,而小淵和小軒被安排在矩陣對角線的兩端,因此,他們就無法直接交談了。幸
【【henuacm2016級暑期訓練】動態規劃專題 D】Writing Code
set 方案 pen col txt clu 二維 stream bit 【鏈接】 我是鏈接,點我呀:) 【題意】 在這裏輸入題意 【題解】 二維費用背包。 f[i][j][k] 前i個人,寫了j行,bug不超過k的方案數。 可以把每個人看成是一個物品。 它
【【henuacm2016級暑期訓練】動態規劃專題 J】Red-Green Towers
cin 使用 space open ble .net long clu 不用 【鏈接】 我是鏈接,點我呀:) 【題意】 在這裏輸入題意 【題解】 顯然最多1000行的樣子。 從上到小做dp 設f[i][j]為前i行,使用了j個紅色方塊的方案數。 f[1][r
Exploring Pyramids【動態規劃——區間DP】
Exploring Pyramids UVALive - 3516 題目傳送門 題目大意:給你一個字串,其代表的是機器人來回走過的路徑,機器人總是先走左邊再走右邊,問有多少種情況。 解決方法:設輸入序列為S,d(i,j)為子序列Si,Si+1,…,Sj對應
動態規劃解決揹包問題
1 揹包問題:給定n個重量為w1,w2...wn,價值為v1,v2...vn的物品和一個承重量為W的揹包,求這些物品中最有價值的一個子集,並且要能夠裝入揹包當中。 2 動態規劃:動態規劃與分治法都要求原問題的最優子結構,都是將問題分而治之,,不同的是動態規劃適用於交疊子問題的情況,分治法則適用於子問題相互獨
動態規劃 -- 01揹包案例(python)
01揹包 m個物品價值為 p[m],體積為 w[m],現有一個容量為 v 的揹包,怎麼裝物品價值最大? 我們嘗試用動態規劃來解決這個問題 一般來說,只要問題可以劃分成規模更小的子問題,並且原問題的最優解中包含了子問題的最優解(即滿足最優子化原理),則可以
C++ 動態規劃 01揹包+ 最大字陣列和 +最短路徑 +斐波那契數列
int max(int a,int b) { return a>b?a:b; } /* 0 1 揹包 */ int MaxValue() { int Weight[5]={2,2,6,5,4};//物品的重量陣列 int Value
P2760 科技莊園-動態規劃,揹包
Life種了一塊田,裡面種了有一些桃樹。 Life對PFT說:“我給你一定的時間去摘桃,你必須在規定的時間之內回到我面前,否則你摘的桃都要歸我吃!” PFT思考了一會,最終答應了! 由於PFT的數學不好!它並不知道怎樣才能在規定的時間獲得最大的價值, 由於PFT不是
動態規劃——01揹包問題
package pack01; public class PackTest_01 { public static void main(String[] args) { // TODO Auto-generated method stub
987C___Three displays——動態規劃(揹包+思維)
題目連結:點我 題目大意: nnn個物品,每個物品體積為sis_isi,花費為cic_ici,每次選333個物品,使這三個物品i<j<ki<j<ki<j<k,並且si<