揹包 DP 終極總結

2022-09-14 19:27:14 字數 2838 閱讀 2346

選擇一組有每一組的貢獻值,有選擇的上限,詢問貢獻值的題目

\(0/1\) 揹包:

這裡需要注意一下的就是節省一維,需要倒序列舉的 \(o(nw(揹包上限))\) 的寫法:

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

for(int j=w;j>=w[i];j--)

if(dp[j-w[i]]+v[i]>dp[j]) dp[j]=dp[j-w[i]]+v[i];

完全揹包:

可以重複列舉,因此是正序的寫法:

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

for(int j=w[i];j<=w;j++)

if(dp[j-w[i]]+v[i]>dp[j]) dp[j]=dp[j-w[i]]+v[i];

多重揹包

也是 \(0/1\) 揹包的變式,每種物品 \(k_i\) 個。

我們把它轉換成 \(0/1\) 揹包即可,每個物品分開計算。

二進位制分組優化

把多個物品拆成:

\(1,2,4,8...(n-?)\) 個物品的加和形式,避免進行重複工作.

過程還是跟 \(0/1\) 揹包一樣。

例題:[heoi2013]eden 的新揹包問題 我的題解

通過單調佇列,降低一維的搜尋時間,因為單調佇列是 \(o(n)\) 的演算法。

基本形態: 當前狀態的所有值可以從上乙個狀態的某個連續的段的值得到,要對這個連續的段進行 \(rmq\) 操作,相鄰狀態的段的左右區間滿足非降的關係。

實在不行暴力也可以....

例題:cf372c watching fireworks is fun 我的題解

單調佇列優化多重揹包

樸素的狀態轉移方程:

\[f_= \max\limits^_(f_,}+v_i*k)

\]時間複雜度為 \(o(m\sum k_i)\)

考慮優化 \(f_i\) 的轉移,設 \(g_=f_,}\),繼續設:

\[g_=f_,}-v_i * x

\]則方程可以表示為:

\[g_= \max\limits^_(g_,})+v_i * x

\]這樣就可以單調佇列對 \(g\) 進行優化,時間複雜度降為 \(o(nw)\) 。

就是將前面三種的揹包問題融合起來,合併就行。

就是多開一維陣列記錄一下另外一組費用,和平時的揹包問題解決方法一樣。

儘量減少維數即可。

例題:p1855 榨取kkksc03

就是將物品分組,每組的物品相互衝突,最多只能選一種物品。

其實就是從在所有物品中選擇一件變成從當前組選擇一件,對每一組進行 \(0/1\) 揹包即可。

例題:p1757 通天之分組揹包

#includeusing namespace std;

const int n=10005;

int n,m,t;

int w[n],v[n],dp[n],b[n];

int g[305][305];

int main()

for(int i=1;i<=t;i++)

for(int j=n;j>=0;j--)

for(int k=1;k<=b[i];k++)//記錄標號的對應的值和大小

if(j>=w[g[i][k]])

dp[j]=max(dp[j],dp[j-w[g[i][k]]]+v[g[i][k]]);

cout《如果選第 \(i\) 個,就必須選第 \(j\) 個,保證不會迴圈引用。

不依賴別的物品的物品,稱為主件。否則稱為輔件。

對於 \(dp\) 有以下可能性:

只選擇主件

選擇主件,再選擇乙個附件

選擇主件,再選擇....個附件

需要將以上可能性的容量和價值轉化成一件件物品,因為這幾種可能性只能選一種,可以看成分組揹包。

讀入時,如果是附件,就把其定義為揹包主件的一部分,計算值,然後在狀態轉移中,列舉選擇情況。

如果是多叉樹的集合,則先運算元節點,再算父節點。

例題:[noip2006 提高組] 金明的預算方案

記錄下來揹包的某乙個狀態是怎麼推導出來的。

我們用 \(g[i][v]\) 表示第 \(i\) 件物品占用空間為 \(v\) 時是否選擇了此物品,然後在轉移時記錄選用了哪一種策略。

偽**:

int v = v; // 記錄當前的儲存空間

// 因為最後一件物品儲存的是最終狀態,所以從最後一件物品進行迴圈

for (從最後一件迴圈至第一件) else

未選第 i 項物品;

}

對於給定的乙個揹包容量、物品費用、其他關係等的問題,求裝到一定容量的方案總數。

這種問題就是把求最大值換成求和即可。

就是 \(dp[i]=\sum (dp[i],dp[i-c[i]])\) ,初始為 \(dp[0]=1\).

這裡的最優方案是指物品總價值最大的方案。以 \(01\) 揹包為例。

結合求最大總價值和方案總數兩個問題的思路,最優方案的總數可以這樣求:

\(dp[i][v]\) 意義同之前,\(g[i][v]\) 表示這個子問題的最優方案的總數

則在求 \(dp[i][v]\) 的同時求 \(g[i][v]\) 的偽**如下:

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

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

差不多就這麼多了.....更多可以到 \(oi-wiki\) 或者揹包九講繼續看

dp揹包問題總結

leetcode題解回答 jackie.yl 常見的揹包問題分為三種 組合問題公式 dp i dp i num true false問題公式 dp i dp i or dp i num 最大最小問題公式 dp i min dp i dp i num 1 或者dp i max dp i dp i nu...

揹包 DP 揹包

揹包 題目 是dp中較為常見的題目 分為 0 1 揹包 完全揹包 和多重揹包 這三類 是越來越深入的首先來介紹一下 0 1揹包 首先 0 1 揹包的含義是 給你乙個容量位m的揹包 然後給你n個物品 每個物品具有一定價值和一定重量 會站一定的揹包空間 答案是在n個物品中那幾個 然後使得到的價值最大 首...

揹包dp之01揹包

現在我們有n個配件,他們有不同的價值.但是我們揹包的容量是有限的,因為我們只有乙個一級包,所以我們最多可以裝v重量的東西.但是為了能更好的吃到雞 不存在的 我們要攜帶更有價值的配件,請問我們最多能拿多少價值的配件來當快遞員呢?輸入的第一行是t,表示有一共要打t場比賽.每組資料由三行組成.第一行包含兩...