單調佇列優化的揹包問題

2021-08-28 23:18:31 字數 2764 閱讀 4129

對於揹包問題,經典的揹包九講已經講的很明白了,本來就不打算寫這方面問題了。

但是吧。

我發現,那個最出名的九講竟然沒寫佇列優化的揹包。。。。

那我必須寫一下咯嘿嘿,這麼好的思想。

我們回顧一下揹包問題吧。

題目 有n件物品和乙個容量為v的揹包。第i件物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。 

這是最基礎的揹包問題,特點是:每種物品僅有一件,可以選擇放或不放。 

f[i][v]表示前i件物品恰放入乙個容量為v的揹包可以獲得的最大價值。則其狀態轉移方程便是:

f[i][v]=max。 

就是說,對於本物品,我們選擇拿或不拿

比如費用是3.

我們求**中黃色部分,只和兩個黑色部分有關

拿了,揹包容量減少,我們價值加上減少後最大價值。

不拿,最大價值等於沒有這件物品,揹包不變,的最大價值。

題目 有n種物品和乙個容量為v的揹包,每種物品都有無限件可用。第i種物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。 

基本思路 

這個問題非常類似於01揹包問題,所不同的是每種物品有無限件。

因為我們拿了本物品還可以繼續拿無限件,對於當前物品,無論之前拿沒拿,還可以繼續拿,所以是f[i][v-c[i]]+w[i]

換乙個角度說明這個問題為什麼可以f[i][v-c[i]]+w[i],也就是同一排。

其實是這樣的,我們對於黃色部分,也就是當前物品,有很多種選擇,可以拿乙個,兩個。。。一直到揹包容量不夠了。

也就是說,可以不拿,也就是j1,可以拿乙個,也就是g1+w[i],也可以拿兩個,也就是d1+2w[i],拿三個,a1+3w[i]。

但是我們看g2,g2其實已經是之前的最大了:a1+2w[i],d1+w[i],g1他們中最大的,對麼?

既然g2是他們中最大的。

我們怎麼求j2?

是不是只要求g2+w[i]和j1的最大值就好了。

因為g2把剩下的情況都儲存好了。

題目 有n種物品和乙個容量為v的揹包。第i種物品最多有n[i]件可用,每件費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。 

和之前的完全揹包不同,這次,每件物品有最多拿n[i]件的限制。

思路一:我們可以把物品全都看成01揹包:比如第i件,我們把它拆成n[i]件一樣的單獨物品即可。

思路二:思路一時間複雜度太高。利用二進位制思路:乙個n位二進位制,能表示2^n種狀態,如果這些狀態就是拿了多少物品,我們可以把每一位代表的數都拿出來,比如n[i]=16,我們把它拆成1,2,4,8,1,每一堆物品看成乙個單獨物品。

為什麼最後有個一?因為從0到16有十七種狀態,四位不足以表示。我們最後補上第五位1.

把拆出來的物品按01揹包做即可。

思路三:我們可以利用單調佇列:

再回想完全揹包:為什麼可以那麼做?因為每件物品能拿無限件。所以可以。而多重揹包因為有了最多拿多少的限制,我們就不敢直接從g2中拿數,因為g2可能是拿滿了本物品以後才達到的狀態 。

比如n[i]=2,如果g2的狀態是2w[i],拿了兩個2物品達到最大值,我們的j2就不能再拿本物品了。

如何解決這個問題?就是我給的**中的,雙端單調佇列

利用視窗最大值的思想。

大家想想怎麼實現再看下文。

發現問題了嗎?

我們求出j2以後,按原來的做法,是該求k2的,但是k2所需要的資訊和j2完全不同,紅色才是k2可能需要的資訊。

所以我們以物品重量為差,先把黑色系列推出來,再推紅色系列,依此類推。

這個例子就是推三次,每組各元素之間差3.

這樣就不會出現構造一堆單調佇列的尷尬情況了。

在**中繼續詳細解釋:

//輸入

int n;

int w;

int w[max_n];

int v[max_n];

int m[max_n];

int dp[max_n+1];//壓空間,本知識參考

int deq[max_n+1];//雙端佇列,儲存下標

int deqv[max_n+1];//雙端佇列,儲存值

佇列存的就是所有上一行能取到的範圍,比如對於j2,佇列裡存的就是g1-w[i],d1-2w[i],a1-3w[i]等等合法情況。(為了操作方便都是j,利用差實現最終的運算)

他們之中最大的就是隊頭,加上最多儲存個數就好。

void solve()}}

}

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

樸素更新 for int i 0 i n i 由 f j max f j f j v w,f j 2 v 2 w,可以觀測到 f j f j v f j 2v f r r j v 是一類,即後面的j只會通過同類的前面元素遞迴過來 因此可以分成如下幾類 f 0 f v f 2v f kv f 1 f ...

單調佇列優化多重揹包

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