多重揹包,想必看到這篇博文的人應該都知道了,這裡僅僅列出偽**($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 ...