【揹包問題】

【01揹包】

描述:給定物品總數\(n\),揹包承重能力\(m\),物品價值\(v[i]\),物品重量\(w[i]\),求知足不超過揹包承重能力的物品最大價值,每種物品只有一件。
解法:
\(f[j]\)表示物品總重爲\(j\)時,物品的最大總價值。
那麼轉移方程爲函數

for(int i=1;i<=n;++i){//枚舉物品
    for(int j=m;j>=w[i];--j){//枚舉物品總重
        f[j]=max(f[j],f[j-w[i]]+v[i]);
    }
}return f[m];

正確性:每次轉移時\(f[j-w[i]]\)還沒有被物品\(i\)嘗試更新,故每一個狀態最多被當前物品更新一次。優化

【徹底揹包】

描述:給定物品種類數\(n\),揹包承重能力\(m\),物品價值\(v[i]\),物品重量\(w[i]\),求知足不超過揹包承重能力的物品最大價值,每種物品有無限件。
解法:
\(f[j]\)表示物品總重爲\(j\)時,物品的最大總價值。
那麼轉移方程爲spa

for(int i=1;i<=n;++i){
    for(int j=w[i];j<=m;++j){
        f[j]=max(f[j],f[j-w[i]]+v[i]);
    }
}return f[m];

正確性:每次轉移時\(f[j-w[i]]\)已經被物品\(i\)嘗試更新,故每一個狀態會被物品儘量多地更新(填滿爲止)。code

【多重揹包】

描述:給定物品種類數\(n\),揹包承重能力\(m\),物品價值\(v[i]\),物品重量\(w[i]\),求知足不超過揹包承重能力的物品最大價值,每種物品有\(c[i]\)件。
解法:
\(f[j]\)表示物品總重爲\(j\)時,物品的最大總價值。
那麼轉移方程爲隊列

for(int i=1;i<=n;++i){
    for(int k=1;k<=c[i];++k){
        for(int j=m;j>=w[i];--j){
            f[j]=max(f[j],f[j-w[i]]+v[i]);
        }
    }
}return f[m];

正確性:每種物品都以01揹包的方式嘗試更新了\(c[i]\)件。class

【多重揹包的優化】

①二進制優化
將多重揹包拆分紅\(\log c[i]\)塊使得這些塊的組合能表達\(1~c[i]\)全部的數值。二進制

for(int i=1;i<=n;++i){
    scanf("%d%d%d",&v[0],&w[0],&c[0]);
    for(int j=1;j<=c[0];j<<=1){
        v[++cnt]=v[0]*j;
        w[cnt]=w[0]*j;
        c[0]-=j;
    }if(c[0]) v[++cnt]=v[0]*c[0],w[cnt]=w[0]*c[0];
}for(int i=1;i<=cnt;++i){
    for(int j=m;j>=w[i];--j){
        f[j]=max(f[j],f[j-w[i]]+v[i]);
    }
}return f[m];

②單調隊列優化
這個會了二進制優化就不必學了吧,揹包問題用這個優化不了多少。co

【分組揹包】

描述:給定物品個數\(n\),揹包承重能力\(m\),物品價值\(v[i]\),物品重量\(w[i]\),求知足不超過揹包承重能力的物品最大價值,每種物品屬於\(c[i]\)組,每組物品中只能選一個。
解法:
\(f[j]\)表示物品總重\(j\)時,物品的最大總價值
那麼轉移方程爲math

int x,p[MAXC][MAXN];
for(int i=1;i<=n;++i) scanf("%d%d%d",&v[i],&w[i],&x),p[x][++p[x][0]]=i;
for(int i=1;i<=MAXC;++i){
    for(int j=m;j>=0;--j){
        for(int k=1;k<=p[i][0];++k){
            if(w[p[i][k]]<=j) f[j]=max(f[j],f[j-w[p[i][k]]]+v[p[i][k]]);
        }
    }
}

正確性:每一個組別的每件物品在互相沖突的前提下進行更新。枚舉

泛化物品

描述:\(v[i]\)\(w[i]\)成函數關係。
解法:按照分組揹包方式枚舉\(w[i]\)求解便可。

混合揹包

描述:每種物品可能能夠屢次使用,也能夠只有一個,有的能夠無限使用,有的\(v[i]\)\(w[i]\)成函數關係。 解法:分類討論便可。

相關文章
相關標籤/搜索