多重揹包單調佇列優化

2022-06-20 07:06:08 字數 1555 閱讀 2340

以一維為例

\(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 ...