以一維為例
\(n\)個物品,揹包容量為\(m\)
\(w_i\) 為體積 \(v_i\) 為收益 \(c_i\) 為限制數量
方程$ f_i=max(f_+pv_i), (i/w_i
觀察上圖,對於i這個物品,所有橙色的部分只會由橙色的部分轉移過來,並且也只能轉移到橙色的部分。
所以,對於一種物品 i 可以按照對 \(w_i\) 的取模結果分成 \(w_i\)
\((w_i \in [0,w_i-1])\) 族,同族之間相互轉移,不同族互不影響。
考慮餘數 \(u \in [0,w_i-1]\) ,對所有餘數分組
對於當前餘數,列舉選擇此物品的個數\(p\in[0,(m-u)/w_i]\)由於物品i最多只能取\(c_i\)個,則有方程
\(f_=max(f_+(p-k)*v_i)\)
\(,(p-c_i
化簡一下柿子
\(f_=max(f_-k*v_i)+p*v_i\)
\(,(p-c_i
因為是一維的,所以我們的p一定是倒序列舉的,那麼\(p-c_i\)遞減,\(p-1\)也是遞減的,顯然\(max\)裡的東西可以用單調佇列維護。 那麼方程的轉移就是線性的了。
外層列舉\(n\)個物品 \(o( n )\)
內層兩個迴圈
其實仔細思考就會發現,這兩個迴圈本質上是遍歷了一遍\(f\)陣列,單調佇列是線性的,所以這裡的複雜度是 \(o( m )\)
總複雜度是 \(o (nm)\)
比樸素解法\(o(m\sum\limits_^nc_i)\)和
二進位制優化 \(o(nmlog_2c)\)都要優秀
上述過程並不太好理解,可以結合模板**進行理解
【模板】多重揹包優化
單調佇列優化**
#include #include #include #include #include using namespace std;
#define int long long
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define _rep(i,x,y) for(int i=x;i>=y;i--)
#define n 40010
const int inf=1e18;
inline int read()
int n,m,v[n],w[n],c[n],q[n],f[n],h,t;
signed main()
//提前將第一批決策點加入單調佇列
_rep(p,maxp,0*1ll)
}} }
int ans=-inf;
rep(i,0,m) ans=max(ans,f[i]);
cout閒話
其實這題二進位制優化也能過
關於二進位制優化,參考我的這篇blog
寫得很爛就是了
多重揹包單調佇列優化思路 單調佇列優化多重揹包問題
6.多重揹包問題 iii acwing題庫 www.acwing.com 揹包九講bilibili www.bilibili.com 從公式中可以看出f j 和f j c 都是從s 1個數裡面取最大值,計算f j c 時只是將滑動視窗右移了一步,類似下圖的效果 只不過移動的時候,前面的s個元素都增加...
單調佇列優化多重揹包
多重揹包的最原始的狀態轉移方程 令 c i min num i j v i f i j max f i 1 j k v i k w i 1 k c i 這裡的 k 是指取第 i 種物品 k 件。如果令 a j v i b j v i 那麼 j a v i b.這裡用 k 表示的意義改變,k 表示取第...
單調佇列優化多重揹包
多重揹包 n個物品,揹包承重m,每個物品 重量 wi 價值vi 個數為ci 普通多重揹包複雜度 o nmc for int i 1 i n i for int j 1 j m j for int k 1 k c i k w i j k f i j max f i j f i 1 j k w i k ...