背包DP

01背包
有N件的品和一个容量为V的背包
第I件物品的体积是c[i],价值是w[i]
求解将哪些物品装入背包可使价值总和最大
TIPS:考虑f[i][j]表示前i件物品恰放入一个容量为j的背包可以获得的最大价值
for(int i=0;i<n;i++)//枚举物品
    for(int j=v;j>=c[i];j--)//递减枚举体积
        f[j]=max(f[j],f[j-c[i]]+w[i]);//压缩维度
//若要求恰好装满,则f[0]=0,f[1...v]=-∞
//若没有要求必须装满,则f[0...v]=0

完全背包
有N种的物品和一个容量为V的背包
每种物品都有无限件可用
第i种物品的费用是c[i],价值是w[i]
求解将哪些的物品装入背包可使这些物品的费用总和不超管背包容量
且价值总和最大
for(int i=0;i<n;i++)//枚举物品
    for(int j=c[i];j<=v;++j)//递增枚举体积
        f[j]=max(f[j],f[j-c[i]]+w[i]);

多重背包
有N种物品和一个容量为V的背包
第I种物品最多有n[i]件可用
每件费用是c[i],价值是w[i]
求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量
且价值总和最大
将该物品拆成1,2,4,2^k,n[i]-2^(k+1)+1共k+1个
for(int i=0;i<n;i++){
    for(int k=1;k<n[i];n[i]-=k,k<<=1)
        for(int j=v;j>=k*c[i];--j)
            f[j]=max(f[j],f[j-k*c[i]]+k*w[i]);
    for(int j=v;j>=n[i]*c[i];--j)
        f[j]=max(f[j],f[j-n[i]*c[i]]+n[i]*w[i]);
}

二维背包
对每件物品,具有两种不同费用;
选择这件物品必须同时付出这两种代价;
对每种代价都有一个可付出的最大值(背包容量)
问:怎样选择物品可以得到最大的价值
解:设这两种代价为代价1和代价2;
第i件物品所需两种代价为a[i]和b[i];
两种代价可付出的最大值(两种背包容量)分别为v,u,物品价值为w[i];
费用加了一维,只需状态也加一维即可
设f[i][v][u]表示前i件物品付出两种代价分别为v,u时可获最大价值
f[i][v][u]=max{f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+w[i]}
同样可以降维,只使有二维数组
当每件物品只可以取一次时变量v和u采有逆序的循环,当物品有如完全背包问题时采有顺序的循环

分组背包
有N件物品和一个容量为V的背包,第I件物品的费用是c[i],价值是w[i]
这些物品被划分为若干组,每组中的物品互相冲突,最多选一件
问:将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大
解:这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选
设f[k][v]表示前K组物品花费费用v能取得的最大权值
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]}
其中物品i属于组k
vector<vector<int>>g;
for(int k=0;k<g.size();k++)//枚举组
    for(int j=v;j;j--)//枚举容量
        for(int i=0;i<g[k].size();i++)
        {//枚举物品
            int p=g[k][i];
            if(j<c[p])continue;
            f[j]=max(f[j],f[j-c[p]]+w[p]);
        }

猜你喜欢

转载自blog.csdn.net/cj1064789374/article/details/84924237