完全背包

完全背包

背包容量为 V V V,有 n n n种物品,每种物品有无限多个,第 i i i种物品体积为 c i c_i ci,价值为 w i w_i wi,怎样装填背包使总价值最大?

实际上,完全背包并不代表每种物品可以真正装填“无限”多个,因为存在背包总体积这一限制因素。

分析:闫氏DP分析法

  • 状态表示

    • 集合:定义数组 d p [ i ] [ j ] dp[i][j] dp[i][j],表示当前选取方案的价值。第 i i i行表示只考虑前 i i i种物品的放置情况, j j j表示当前选取体积不超过 j j j的方案集合。 i n i t ( d p [ 0 ] [ i ] , d p [ j ] [ 0 ] ) = 0 init(dp[0][i],dp[j][0])=0 init(dp[0][i],dp[j][0])=0
    • 属性: M a x Max Max
  • 状态计算: d p [ i ] [ j ] dp[i][j] dp[i][j]:对于第 i i i种物品:

    • 不可选第 i i i种物品:当 v < c [ i ] v<c[i] v<c[i]时,无法装入背包,背包剩余容积不变。集合状态仍为 [ 1 , i − 1 ] [1,i-1] [1,i1],直接继承自第 i − 1 i-1 i1种物品且背包容积仍为 j j j方案的价值。 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j]
    • 可选第 i i i种物品:
      • 不选第 i i i种物品:若选第 i i i种物品无法保证最优解,则不选,背包剩余容积不变。集合状态仍为 [ 1 , i − 1 ] [1,i-1] [1,i1],直接继承自第 i − 1 i-1 i1种物品且背包容积仍为 j j j方案的价值。 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j]
      • [ 1 , . . . , k , . . . + ∞ ] [1,...,k,...+\infty] [1,...,k,...+]个第 i i i种物品:选第 i i i种物品可能导致产生最优解,则选。集合状态变为 [ 1 , i ] [1,i] [1,i],因为第 i i i种物品可被选多次,设选 k k k个第 i i i种物品,则继承自第 i i i种物品且背包容积 j j j减少 k ∗ c [ i ] k*c[i] kc[i]方案的价值,并加 k ∗ w [ i ] k*w[i] kw[i]。对于每一次选第 i i i种物品,为 d p [ i ] [ j ] = d p [ i ] [ j − c [ i ] ] + w [ i ] dp[i][j]=dp[i][j-c[i]]+w[i] dp[i][j]=dp[i][jc[i]]+w[i]
  • 状态转移方程式: d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − c [ i ] ] + w [ i ] ) dp[i][j]=max(dp[i-1][j],dp[i][j-c[i]]+w[i]) dp[i][j]=max(dp[i1][j],dp[i][jc[i]]+w[i])

遍历顺序:物品和背包谁先遍历都可以

void init(){
    for(int i=0;i<=n;i++) dp[i][0]=0;
    for(int i=0;i<=v;i++) dp[0][j]=0;
}
int dp(){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=v;j++)
            if(c[j]<v) dp[i][j]=max(dp[i-1][j],dp[i][j-c[i]]+w[i]);
    		else dp[i][j]=dp[i-1][j];
    return dp[n][v];
}

时间复杂度 O ( n 3 ) O(n^3) O(n3),空间复杂度 O ( n v ) O(nv) O(nv)

滚动优化

交替滚动

extern int dp[2][v];
int dp(){
    int work=0,old=1;
    for(int i=1;i<=n;i++){
        swap(work,old);
        for(int j=1;j<=v;j++)
            if(c[i]<=j) dp[work][j]=max(dp[old][j],dp[work][j-c[i]]+w[i]);
    		else dp[work][j]=dp[old][j];
    }
    return dp[work][v];
}

自我滚动

遍历顺序:物品背包谁先遍历都可以,且均为顺序遍历

extern int dp[v];
int dp(){
    for(int i=1;i<=n;i++)
        for(int j=c[i];j<=v;j++)//c[i]之前的不用管
            dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
    return dp[v];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值