揹包問題小結

2021-10-05 12:00:33 字數 3396 閱讀 4119

這個周好好總結了揹包問題,下面簡單總結一下揹包問題,也方便以後忘了可以來複習

揹包問題最基礎的就是01揹包,其他的揹包問題都可以通過新增各種附加條件這樣的方式轉化為01揹包。01揹包就按字面意思來理解,每個物品只有一件,0是false1是true就是這件物品裝還是不裝,做出選擇,根據這個選擇我們也可以寫出狀態轉移方程,定義乙個二維陣列f[i][v]表示前i件物品部分或全部放入容量為v的揹包可以獲得的最大價值,根據題意如果第i件物品不放入揹包,那麼當前揹包的最大價值和前一件物品的狀態是相同的,那麼狀態轉移方程就是f[i][v]=f[i-1][v],如果第i件物品不放入揹包,狀態轉移方程就是f[i][v]=f[i-1][v-w[i]]+c[i],w[i]是第i件物品的重量,c[i]是第i件物品的價值,解釋一下就是如果第i件物品放入揹包,那麼當前揹包的價值就等於在前一件物品,並且揹包裡沒有第i件物品的最大價值再加上第i件物品的價值。最後取出二者的最大值即可,即

f[i][v]=max(f[i-1][v-w[i]]+c[i],f[i-1][v]);
用二維陣列f[maxn][maxn]儲存子問題的時候,如果maxn超過2000就會超過記憶體限制,**沒辦法執行,這個時候我們可以用一位陣列的模式來優化空間複雜度,即

f[v]=max(f[v],f[v-w[i]]+c[i]);
意思的話跟二維陣列沒有太大區別,一看就能明白

看一道01揹包的遍歷

時間限制: 1000 ms         記憶體限制: 65536 kb

提交數: 12659     通過數: 7806乙個旅行者有乙個最多能裝 mm 公斤的揹包,現在有 nn 件物品,它們的重量分別是w1,w2,...,wnw1,w2,...,wn ,它們的價值分別為c1,c2,...,cnc1,c2,...,cn ,求旅行者能獲得最大總價值。

第一行:兩個整數,mm (揹包容量,m≤200m≤200 )和nn (物品數量,n≤30n≤30 );

第2..n+12..n+1 行:每行二個整數wi,ciwi,ci ,表示每個物品的重量和價值。

僅一行,乙個數,表示最大總價值。

10 4

2 13 3

4 57 9

12

#includeusing namespace std;

const int n=201;

int qread ()

while (ch>='0'&&ch<='9')

return x*f;

}int i,j,m,n,wi,ci,f[n]=;

int main ()

} cout<<"max="《接下來就是多重揹包問題,介紹概念的例題就是慶功宴,這個問題的區別就是有n種物品,每種物品並不是每件都可用,會有乙個n[i]陣列儲存每種物品可用的數量,這個問題的基本方程需要將完全揹包的方程做一下更改,對於第i件物品有n[i]+1種策略,取0件1件直到n[i]件,令f[i][v]表示前i種物品放入揹包的最大價值 

狀態轉移方程就是

f[i][v]=max(f[i-1][v-k*w[i]]+k*c[i],f[i-1][v]);

下面看一下慶功宴這道題目

時間限制: 1000 ms         記憶體限制: 65536 kb

提交數: 8353     通過數: 4811為了慶賀班級在校運動會上取得全校第一名成績,班主任決定開一場慶功會,為此撥款購買獎品犒勞運動員。期望撥款金額能購買最大價值的獎品,可以補充他們的精力和體力。

第一行二個數n(n≤500),m(m≤6000),其中n代表希望購買的獎品的種數,m表示撥款金額。

接下來n行,每行3個數,v、w、s,分別表示第i種獎品的**、價值(**與價值是不同的概念)和能購買的最大數量(買0件到s件均可),其中v≤100,w≤1000,s≤10。

一行:乙個數,表示此次購買能獲得的最大的價值(注意!不是**)。

5 1000

80 20 4

40 50 9

30 50 7

40 30 6

20 20 1

1040

#include#include#include#includeconst int maxn = 6005;

using namespace std;

int w[maxn],c[maxn],p[maxn],dp[maxn];

int main()

} }cout《剩下的分組揹包和二維費用揹包都不是很常見就先沒有總結

再看兩道我這個周做的vj的揹包問題

電子科大本部食堂的飯卡有一種很詭異的設計,即在購買之前判斷餘額。如果購買乙個商品之前,卡上的剩餘金額大於或等於5元,就一定可以購買成功(即使購買後卡上餘額為負),否則無法購買(即使金額足夠)。所以大家都希望盡量使卡上的餘額最少。 

某天,食堂中有n種菜**,每種菜可購買一次。已知每種菜的**以及卡上的餘額,問最少可使卡上的餘額為多少。 

input

多組資料。對於每組資料: 

第一行為正整數n,表示菜的數量。n<=1000。 

第二行包括n個正整數,表示每種菜的**。**不超過50。 

第三行包括乙個正整數m,表示卡上的餘額。m<=1000。 

n=0表示資料結束。 

output

對於每組輸入,輸出一行,包含乙個整數,表示卡上可能的最小餘額。

sample input

1505

101 2 3 2 1 1 2 3 2 1

500

sample output

-45

32

起初我的思路是先把**公升序排序,然後拿餘額乙個乙個減,減到最接近5的時候停止,最後再減去最大的那個**然後輸出,說到底用了貪心的想法,每次減最小的然後結果最接近5,其實不然。

例如這組資料,如果用貪心的話,最多剩10-1-3=6,但明顯10-5=5比6小,可見貪心是不行的

這就用到了動態規劃裡的01揹包問題了

#include#include#include#includeusing namespace std;

int a[1100],dp[1100];

int main()

} int ans;

for(int i = 0; i <= 366; ++i)

} printf("%d\n", ans);

}}

最後說一下這個周做cf的題目情況吧,明明是一道很簡單的題目,當時我不管是用暴力還是dp都做不出來,而事後看題解就發現其實是一道很簡單dp題目,這樣就讓我很困惑,感覺做dp題目就是這樣其實並不是不會,思路並不難,可就是不會,總結下來還是題解看多了,而題目又做少了,以後我一定克服這些問題。想要做好無非看自己想不想,需要多花時間,希望自己可以做的更好。

揹包問題小結

學演算法的時候,揹包問題是乙個很常見的動態規劃問題,像什麼01揹包 完全揹包 多重揹包等,當時學的時候就有一些懵懵懂懂的,現在複習的時候又不會了,所以進行總結一下,方便日後檢視學習。問題基本上都是lintcode上面的題目,然後在github上還找到乙個專門講揹包問題的倉庫 樣例 1 輸入 3,4,...

揹包基礎小結

揹包學得太差了要好好複習總結一下 01 完全 揹包 揹包問題 有一些物品,每個物品有花費和價值,一般來說求的是在花費不超過給定數的前提下求最大的價值.一般來說會省略第一維,但是在一些問題轉化成的揹包問題中不要忘了這一維可能又會被利用起來.01揹包 v表示花費 w表示價值 go i,1,n yes j...

樹形揹包小結

已知 2 1 種做法 分別是 link bzoj2427 int sta n dfn n low n w n val n dp n 505 n,m,top,w n v n fa n l n cnt n siz n bel n idx vint g n bitsetins,vis void tarja...