【笔记+代码】背包问题

n个物品 背包容量W
w[i] 费用,v[i] 价值;

01背包

每件物品选或不选。

板子:

void zerone(int wei,int val){
    for(int j=W;j>=wei;j--) d[j]=max(d[j],d[j-wei]+val);
}
for(int i=1;i<=n;i++)
    zerone(w[i],v[i])

超大01背包

每个物品只能拿一次,物品数量M<=100,背包容量T<=10^9,每个物品的价值<=100,每个物品的重量<=10^9
将dp数组第二维变为价值,存储达到价值j所需的最小重量

dp[i][j]=min(dp[i][j],dp[i-1][j-v[i]]+w[i])

在dp[n][j]<=W里找最大的j

完全背包

每件物品可以选无数次。

void wanquan(int wei,int val){
    for(int j=wei;j<=W;j++) d[j]=max(d[j],d[j-wei]+val);
}
for(int i=1;i<=n;i++)
    wanquan(w[i],v[i])
数竞大佬的证明思路
①dp[i][j]max=dp[i-1][j-k*w[i]]+k*v[i]  0<=k
②dp[i][j]max=dp[i-1][j-w[i]-t*w[i]]+t*v[i]+v[i] 0<=t,1<=k
            dp[i-1][j]                          k==0
③dp[i][j-w[i]]max=dp[i-1][j-w[i]-t*w[i]]+t*v[i] 0<=t
将③带入②
dp[i][j]max = dp[i-1][j]
            dp[i][j-w[i]]+v[i]

多重背包

每件物品可以选固定数量次。

二进制拆分

void duochong(int wei,int val,int num){
    if(num*wei>=W) {
        wanquan(wei,val);
        return;
    }
    int k=1;
    while(k<num){
        zerone(wei*k,val*k);
        num-=k;
        k*=2;
    }
    zero(wei*num,val*num);
    return ;
}
for(int i=1;i<=n;i++)
    duochong(w[i],v[i],m[i])

时间复杂度 m*xigema(logk)
二进制拆分的可行性证明(不严格):
k=2^0+2^1+2^2+………2^x+p;
k=(111…….1)(2进制)+p;
那么从0–1111111….1的数,可由2的次幂的选否表示出来。
p<11111…..11(p<2^(x+1)),p+111…111=k;
从11111…..1+1—–k,固定选p,那么要凑的质量-p一定小于1111..1,
有上述结论可知,这个数是可以凑出来的。
证毕;

混合背包

每个物品可以选一件,无数件或给定数量件
解法:对于每件物品,判断是01,完全,多重,分别计算。

for(int i=1;i<=n;i++){
    if(wanquan) wanquan(w[i],v[i]);
    if(01) zerone(w[i],v[i]);
    if(duochong) duochong(w[i],v[i],m[i]);
}

二维费用背包

对于每个物品,有两种费用,每个费用都有最大值;
隐含方式:
最多取m件,这是件数就是另一个费用,每个物品此费用为1

for(int i=1;i<=n;i++){
    for(int j=W;j>=w[i];j--){
        for(int k=U;k>=u[i];k--){//另一个价值u
            dp[j][k]=max(dp[j][k],dp[j-w[i]][k-u[i]]+v[i]); 
        }
    }
}
完全jk顺序循环,多重拆分;

分组背包

所有物品分为k组,每组中至多选择一个物品;

for(int i=1;i<=k;i++) //每组内部 
    for(int j=W;j>=0;j--)//背包总重量 
        for(p)//p是该组内部的物品 
            dp[j]=max(dp[j],dp[j-w[p]]+v[p]);

正确性证明:
一开始以为只要背过代码就可以,结果度娘一搜,发现背包九讲第一版中居然有错误。

http://www.cppblog.com/Onway/archive/2010/08/09/122695.html
%这位不知名大神。

递推式dp[j]=max(dp[j],dp[j-w]+v]
循环顺序 组别,质量,组内物品。
对于每个组内,对每一个质量进行循环,由于j是逆序,dp[j]是上一组决策的结果。
同样由于j是逆序,质量为j-w的背包还未在(第一层循环)本组中决策,故j-w也是上一组决策的结果,保证滚动数组的正确性。

有依赖背包问题

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值