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

2021-10-14 14:49:22 字數 1328 閱讀 8177

6. 多重揹包問題 iii - acwing題庫​www.acwing.com

揹包九講bilibili​www.bilibili.com

從公式中可以看出f[j]和f[j+c]都是從s+1個數裡面取最大值,計算f[j+c]時只是將滑動視窗右移了一步,類似下圖的效果:

只不過移動的時候,前面的s個元素都增加了w,每個元素加上相同的數不影響計算最大值。使用單調佇列可以在o(n)時間複雜度下找到所有滑動視窗的最大值,關於單調佇列處理滑動視窗的問題可以看看這篇文章:

labuladong:特殊資料結構:單調佇列​zhuanlan.zhihu.com

容易知道f[j]的計算只依賴於g[k],其中j%c = k%c。因此可以將g[0~m]按%c的餘數進行分類:

g[0],g[c],g[2c],g[3c],...

g[1],g[1+c],g[1+2c],g[1+3c],...

g[c-1],g[2c-1],g[3c-1],g[4c-1]...

每個分類可以計算出:

f[0],f[c],f[2c],f[3c],...

f[1],f[1+c],f[1+2c],f[1+3c],...

f[c-1],f[2c-1],f[3c-1],f[4c-1]...

從而整個f[0~m]都能計算出來。

上面的講解可能有點囉嗦,歸納起來就兩點:

需要將所有狀態按照%c的餘數進行分類,每個分類可以計算出下一層對應的分類計算下一層對應分類的過程類似於滑動視窗取最大值,利用單調佇列可以實現o(n)的時間複雜度

綜上所述,c++**如下:

#include #include #include #include using namespace std;

int main()

}} cout << f[m] << endl;

return 0;

}

遺憾的是居然超時了。。。。。主要是因為deque.clear()太頻繁了,每次clear都會清空記憶體,也不存在lazy clear的api。沒辦法只能用陣列模擬佇列了。最終提交通過的**如下:

#include #include #include using namespace std;

int main()

}} cout << f[m] << endl;

return 0;

}

說實話,這種第一次不照著答案敲是很難寫對的,不過思路明白了下次寫就容易很多了。

單調佇列優化多重揹包

多重揹包的最原始的狀態轉移方程 令 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 ...

單調佇列優化多重揹包

應該是個經典演算法,稍微記錄一下 用 w i 表示重量,v i 表示價值 那麼不難寫出轉移方程 f i j max f i 1 j k w i k v i 考慮用單調佇列優化。我們若要用單調佇列優化,那麼必須滿足轉移時所需要的狀態只與 k 有關 這裡要用到乙個神仙操作,對 j w i 分類 因為對於...