背包问题中总体积最多/恰好/最少为j的区别

这三个之间的区别主要是在初始化的时候有所不同:(这里的属性是要求最大值)

1、体积最多为j: memset(f,0,sizeof(f)) ,v>=0

2、体积恰好为j:memset(f,-INF,sizeof(f)),f[0]=0,v>=0

3、体积至少为j:memset(f,-INF,sizeof(f)),f[0]=0

AcWing8. 二维费用的背包问题(体积最多是j)
题意:有 N 件物品和一个容量是 V 的背包,背包能承受的最大重量是 M。每件物品只能用一次。
体积是 vi,重量是 mi,价值是 wi。求解将哪些物品装入背包,可使物品总体积不超过背包容量,
总重量不超过背包可承受的最大重量,且价值总和最大。
思路:f[i][j][k]表示从前i件物品中选且总体积不超过V,总重量不超过M的最大价值。
f[i][j][k]=max(f[i-1][j][k],f[i-1][j-v][k-m]+v)。

#include<iostream>
using namespace std;
const int N=110;
int f[N][N];
int n,v,w;
int main()
{
	scanf("%d%d%d",&n,&v,&w);
	for(int i=0;i<n;i++)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		for(int j=v;j>=a;j--)
			for(int k=w;k>=b;k--)
				f[j][k]=max(f[j][k],f[j-a][k-b]+c);
	}
	printf("%d\n",f[v][w]);
	return 0;
}

AcWing 278. 数字组合(体积恰好为j)
题意:给定 N 个正整数 A1,A2,…,AN,从中选出若干个数,使它们的和为 M,求有多少种选择方案。
思路:f[i][j],表示从前i个物品中选且体积恰好为j的方案数。
对于第i个数:①选,f[i-1][j-v[i]];②不选,f[i-1][j];
所以f[i][j]=f[i-1][j-v[i]]+f[i-1][j];
背包恰好装满问题?
怎么保证是恰好装满?用初始化来实现,将所有的f[i]=-INF,f[0]特殊处理,就可以。
因为如果不存在使f[i]满足是恰好装满的,那么这个f[i]=-INF,即一个非法答案,就不会影响最终的计算。
因为它虽然被算进去了,但是f[i]接近-INF(非法答案),不影响结果。
总结:只要保证答案是从f[0](合法)不断转移过来的就行,所以把其它的都预设为不合法。

#include<iostream>
using namespace std;
const int N=110,M=10010;
int f[M];
int a[N];
int n,m;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	f[0]=1;//总和为0的方案数为1
	for(int i=1;i<=n;i++)
		for(int j=m;j>=a[i];j--)
			f[j]=f[j]+f[j-a[i]];
	printf("%d\n",f[m]);
	return 0;
}

AcWing 1020. 潜水员(体积至少是j)
思路:f[i][j][k]:从前i件物品中选花费1至少为j,花费2至少为k的最小价值。
f[i][j][k]=min(f[i-1][j][k],f[i-1][j-v1][k-v2]+w),这里要注意j-v1<0,k-v2<0是合法的情况,要考虑进去。

#include<iostream>
#include<cstring>
using namespace std;
const int N=30,M=80,INF=0x3f3f3f3f;
int f[N][M];
int n,m;
int main()
{
	scanf("%d%d",&n,&m);
	int s,a,b,c;
	scanf("%d",&s);
	memset(f,INF,sizeof(f));
	f[0][0]=0;
	for(int i=0;i<s;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		for(int j=n;j>=0;j--)
			for(int k=m;k>=0;k--)
				f[j][k]=min(f[j][k],f[max(0,j-a)][max(0,k-b)]+c);//对于体积为j-v<0这是一种合法的状态,所以它是要选进去的
	}
	printf("%d\n",f[n][m]);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值