背包问题

01背包

for(int i = 1; i <= n; ++i)
{  
	for(int j = V; j >= c[i]; --j)
	{  
		dp[j] = max(dp[j],dp[j-c[i]]+a[i]);  
	}  
}

完全背包

for(int i = 1; i <= n; ++i)
{  
	for(int j = c[i]; j <= V; j++)//与01背包不同,从前往后刷新即可以重复加物品,手动模拟下就能明白
	{  
		dp[j] = max(dp[j],dp[j-c[i]]+a[i]);  
	}  
}

注意:初始化方面的细节,如果要求恰好装满背包,那么在初始化时除了dp[0]为0其它dp[1..V]均设为-∞(求的是最大解,如果求的是最小解,则为∞)  如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。因为如果恰好背满的话,必须是由状态dp[0]转移而来,所以dp[0]要最靠近最优决策。

多重背包(二进制优化)

for(int i = 1; i <= n; ++i)
{
	int k;
	for(k = 1; k*2 <= count[i]; k *= 2)//count[i]为i物品的个数,本来是一个一个放,现在是成倍的放,比如9,放1、2、4、8
	{
		for(int j = V; j >= k*c[i] ; --j)
		dp[j] = max(dp[j],dp[j-k*c[i]] + k*a[i]);
	}
	k = count[i] - k;
	for(int j = V; j >= k*c[i]; --j)
	dp[j] = max(dp[j],dp[j-k*c[i]] + k*a[i]); 
}

现在dp[i]用来表示容量为i的背包能否被所给物品恰好装满,01背包和完全背包都一样

memset(dp,false,sizeof(dp));
dp[0] = true;
for(int i = 1; i <= N; ++i)
{
	memset(used,0,sizeof(used));
	for(int j = c[i]; j <= V; ++j)
	{
		if(!dp[j] && dp[j-c[i]] && used[j-c[i]] < count[i])
		{
			dp[j] = true;
			used[j] = used[j-c[i]] + 1;
		}
	}
}

混合背包
就是结合上面3种,有的物品只能取一次,有的物品能取无限次,有的物品能取有限次,枚举每个物品,判断是什么类型的背包就用什么方法写。
二维费用背包(多维同理)
比如:每件物品都有各自的体积v[i]和重量w[i],一个背包最多可以装的体积为V,最多可以装的重量为W,问最多能装的价值。就是多了一个限制
以01背包为例:
for(int i = 1; i <= n; ++i)
{  
	for(int j = V; j >= v[i]; --j)
	{
		for (int k=W; k >= w[i]; --k)
		dp[j][k] = max(dp[j][k],dp[j-v[i]][k-w[i]]+a[i]);  
	}
}
分组背包
将n个物品分成若干组,每组只能拿一个,求最大价值

for 所有的组k

    for v=V..0

        for 所有的i属于组k

            dp[v]=max{dp[v],dp[v-c[i]]+a[i]}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值