選擇一組有每一組的貢獻值,有選擇的上限,詢問貢獻值的題目
\(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場比賽.每組資料由三行組成.第一行包含兩...