基於單調佇列的多重揹包優化

2022-05-07 20:03:09 字數 1576 閱讀 6372

​ 多重揹包,想必看到這篇博文的人應該都知道了,這裡僅僅列出偽**($n$為物品個數,$m$為揹包容積)

for i := 1 to n

for j := 0 to m

for k := 0 to c[i]

f[i][j] = max(f[i - 1][j - k * v[i]] + k * w[i])

​ 顯然,這種演算法的複雜度是很不可取的,於是我們來考慮優化

​ 設$c,v,w$分別為當前物品的個數,體積,價值,根據原始轉移方程可知,$f_i$一定是由$f_$轉移而來,所以$c,v,w$不用開陣列(有的$oj$竟然會卡空間...),為了方便說明,以下設陣列$g$表示陣列$f_$,於是方程簡化為:

f[j] = max(g[j - k * v] + k * w) //0≤k≤c
​ 顯然,就算不簡化,我們也能看出:$f_j$只從$f_,f_...f_$轉移過來,且對於每乙個這其中的$j$,都有如下性質:它們模上$v$後的餘數相同,於是我們將其模$v$後的餘數拎出來考慮,迴圈可以這樣寫:

for i := 1 to n

for j := 0 to v - 1

...

​ 接下來呢,就要列舉係數$k$了

for (k = 0; k * v + j <= m; ++k)
​ 你不覺得列舉係數很麻煩嗎?這樣就好了

for (k = j; k <= m; k += v)
​ 接下來來看轉移方程,根據之前得出的轉移方程,顯然我們是要找到在乙個長度為$c$的區間內最大的$g[j - k \times v] + k\times w$,可以用單調佇列來儲存,於是又有

while (l <= r && (k - q[l]) / v >= c) ++l;

while (l <= r && f[i - 1][k] - f[i - 1][q[r]] >= (k - q[r]) / v * w) --r;

q[++r] = k;

f[i][k] = f[i - 1][q[l]] + (k - q[l]) / v * w;

#include #include #include using namespace std;

const int n = 1e3 + 10, m = 1e4 + 10;

int n, m, f[n][m], v, w, c, q[m], l, r, ans;

int main ()

} }

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

ans = max (ans, f[n][i]);

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

return 0;

}

單調佇列初始化為$l=1,r=0$,且在迴圈$j$內初始化

單調佇列長度開到$m$,因為有可能出現$v=1$的情況

最後答案不一定存在$f_$裡面,要在$1...m$掃一遍

一定要記得$c=min(c,m/v)$,為了防止揹包溢位

多重揹包單調佇列優化思路 單調佇列優化多重揹包問題

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