对背包问题的一些总结

sdddf算法中的背包问题可以分为0-1背包问题和完全背包问题。

两者的核心不同在于决策的数量,0-1背包适用于选择某个物体时只能选择一次,而完全背包可以无限次地选择某个物体,这也就直接导致两者的核心式的不同:

0-1背包
int f[m][n];//m代表总共m个物体,n代表背包总体积
for(int i=1;i<=m;i++)
for(int j=V;j>=v[i];j--)
f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);

完全背包
int f[n];//n代表背包总体积
for(int i=1;i<=m;i++)
for(int j=v[i];j<=V;j++)
f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);

对上面核心式进行简化,发现
0-1背包:
for(int j=V;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);

完全背包
for(int j=v[i];j<=V;j++)
f[j]=max(f[j],f[j-v[i]]+w[i]);

只有循环的顺序不一样

当然,通过以上两个基本式可以衍生出许多变式。我们需要从实际问题中抽象出“决策”,从而达到使用背包式的目的。

以0-1背包为例,实际问题中,对于一个目标物体进行处理时,如主附件问题那样,我们不能使用完全背包,需要用到0-1背包,但是0-1背包的两个决策又不能够满足要求,这个时候就需要添加新的决策来完善条件。如下面这个代码所示:

for(int i=1;i<=m;i++){
		for(int j=n;main_item_w[i]!=0&&j>=main_item_w[i];j--){
			f[j]=max(f[j],f[j-main_item_w[i]]+main_item_c[i]);
			 if (j >= main_item_w[i] + annex_item_w[i][1])
                f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] ] + main_item_c[i] + annex_item_c[i][1]);

            if (j >= main_item_w[i] + annex_item_w[i][2])
                f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][2]);

            if (j >= main_item_w[i] + annex_item_w[i][1] + annex_item_w[i][2])
                f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][1] + annex_item_c[i][2]);

		}
	}

而上述代码的背包问题其实都是用来解决最大‘价值’问题的,如果我们需要求解方案数问题,

围绕‘决策’这个思路来,对第i个物品做决策有两个,要么选这个物品,要么不选这个物品,这两个方案是需要相加的

只需对代码进行如下更改:

for(int j=n;j>=w[i];j--){
 f[j]=f[j]+f[j-w[i]];
}

最后,其实搜索类问题和dp问题有着许多相通之处,搜索问题皆可dp,但dp不一定可以搜索。因此做搜索类问题时可以尝试用记忆化搜索、dp来优化复杂度。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值