淺談揹包

01揹包:

問題:有N件物品和一個容量爲V的揹包。第i件物品的體積是w[i],價值是v[i]。求解將哪些物品裝入揹包可以使這些物品的重量總和不超過揹包容量,且價值總和最大。數組

思路:對每種物品咱們能夠選擇用或不用,則有狀態轉移方程\(f[i][j]=max(f[i-1][j-w[i]]+v[i],f[i][j])\)優化

Code:

for(int i=1;i<=n;i++)
    for(int j=1;j<=V;j++)
        if(j>=w[i]) f[i][j]=max(f[i-1][j-w[i]]+v[i],f[i][j])

事實上咱們發現這個方程內當前狀態的轉移之和上一個物品有關,則咱們能夠考慮優化空間spa

咱們倒序dp,數組變成一維,\(f[j]=max(f[j-w[i]]+v[i],f[j])\),倒序dp的緣由是爲了避免覆蓋上次的值code

Code:

for(int i=1;i<=n;i++)
    for(int j=V;j>=1;j--)
        if(j>=w[i]) f[j]=max(f[j-w[i]]+v[i],f[j]);

徹底揹包:

問題:有N件物品和一個容量爲V的揹包。第i件物品的體積是w[i],價值是v[i],每件物品能夠用無限次。求解將哪些物品裝入揹包可以使這些物品的重量總和不超過揹包容量,且價值總和最大。隊列

思路:狀態轉移方程不變,但因爲每件物品能夠用無數次,則不用考慮上件物品的影響,正序dp便可class

Code:

for(int i=1;i<=n;i++)   
    for(int j=1;j<=V;j++)
        if(j>=w[i]) f[j]=max(f[j-w[i]]+v[i],f[j]);

多重揹包:

問題:有N件物品和一個容量爲V的揹包。第i件物品的體積是w[i],價值是v[i],每件物品能夠用u次。求解將哪些物品裝入揹包可以使這些物品的重量總和不超過揹包容量,且價值總和最大。二進制

思路:能夠看作是可取u個的01揹包來作時間

Code:

for(int i=1;i<=n;i++)   
    for(int j=V;j>=1;j--)
        for(int k=1;k<=n;k++)
            if(j>=k*w[i]) f[j]=max(f[j-k*w[i]]+k*v[i],f[j]);

事實上咱們能夠進行優化,能夠將u進行二進制分解,而後再來dp,時間複雜度O(VN log u)while

Code:

int b=1;
while(u){
    if(u&1) a[++cnt]=b;
    b<<=1;u>>=1;
}int t=0;
for(int i=1;i<=n;i++)
    for(int j=1;j<=cnt;j++)
        w0[++t]=w[i]*a[j],v0[t]=v[i]*a[j];
for(int i=1;i<=t;i++)
    for(int j=V;j>=1;j--)
        if(j>=w0[i]) f[j]=max(f[j-w0[i]]+v0[i],f[j]);

然而還有O(VN)的單調隊列優化,然而...我還不會...co

相關文章
相關標籤/搜索