背包模型

1.0 1.0 1.0 01 01 01背包问题

每一个物品只能取 1 1 1 , C + + ,C++ ,C++ 模板 : : :

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,Arr[110];
int Dp[100010];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&Arr[i]);
	Dp[0]=1;
	for(int i=1;i<=n;i++)
		for(int j=m;j>=Arr[i];j--)
			Dp[j]+=Dp[j-Arr[i]];
	printf("%d\n",Dp[m]);//m价值的排列个数
	return 0;
}

2.0 2.0 2.0 完全背包问题

每一个物品能取多次 , C + + ,C++ ,C++ 模板 : : :

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,Arr[110];
int Dp[100010];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&Arr[i]);
	Dp[0]=1;
	for(int i=1;i<=n;i++)
		for(int j=Arr[i];j<=m;j++)
			Dp[j]+=Dp[j-Arr[i]];
	printf("%d\n",Dp[m]);//m价值的排列个数
	return 0;
}

3.0 3.0 3.0 多重背包问题

n n n 种物品 , , , 每个物体有 C n t i Cnt_i Cnti , , , 每一个的价值是 A r r i , Arr_i, Arri, 每一个的体积是 V o l i , Vol_i, Voli, 问容量为 v v v 的背包能装下的价值总和最大的是多少 . . .

3.0.1 3.0.1 3.0.1 直接拆分法

把每个物品拆分成 C n t i Cnt_i Cnti 个物品 , , , 然后再跑一遍带价值的一遍背包 . . .

3.0.2 3.0.2 3.0.2 二进制拆分法

把每个物品分成多个不同的物品 , , , 每个物品的价值 , , , 体积分别为原来的 2 0 , 2 1 , 2 2 ⋯ 2 p 2^0,2^1,2^2\cdots 2^p 20,21,222p ( 2 0 + 2 1 + 2 2 ⋯ + 2 p < C n t i ) , (2^0+2^1+2^2\cdots+2^p<Cnt_i), (20+21+22+2p<Cnti), 余下来的物品在组成一个新物品 , , , 再跑一次带价值的一遍背包即可 . . .

3.0.3 3.0.3 3.0.3 单调队列优化

请见于单调队列优化处.

3.0.4 3.0.4 3.0.4 Acwing281

此题为多重背包问题的特殊情况 , , , 询问可行性 . . .

我们考虑贪心 , , , 动态规划最小消耗 . . .

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,Arr[101],Cnt[101],Dp[2][100011];
int main()
{
	while(~scanf("%d%d",&n,&m)&&(n||m))
	{
		for(int i=1;i<=n;i++)
			scanf("%d",&Arr[i]);
		for(int i=1;i<=n;i++)
			scanf("%d",&Cnt[i]);
		memset(Dp,-1,sizeof(Dp));
		Dp[0&1][0]=0;
		for(int i=1;i<=n;i++)
			for(int j=0;j<=m;j++)
				if(Dp[(i-1)&1][j]>=0)
					Dp[i&1][j]=Cnt[i];
				else if(j-Arr[i]>=0&&Dp[i&1][j-Arr[i]]>=1)
					Dp[i&1][j]=Dp[i&1][j-Arr[i]]-1;
		int ans=0;
		for(int j=1;j<=m;j++)
			if(Dp[n&1][j]>=0)ans++;
		printf("%d\n",ans);
	}
	return 0;
}
/*
若f[j]能被拼出

1.前i-1种硬币就能拼成面值j,即在第i阶段开始前,f[j]已经成为true。

2.使用了第i种硬币,即在第i阶段的递推过程中,发现f[j-a[i]]为true,从而使用一个i硬币,使f[j]变为true。

于是可以考虑一种贪心策略:设used[j]表示在第i阶段下将f[j]变为true至少需要使用多少枚第i种硬币。

为了满足我们的贪心策略,我们应该尽量多的使用第1种情况,也就是说在f[j-a[i]]为true时,若f[j]已经为true,就不进行DP转移,并令used[j]=0(我们并没有使用第i种硬币)仅当f[j-a[i]]为true而f[j]为false且已经使用的i硬币used[j-a[i]]<c[i]时,我们使用一个i硬币使f[j]变为true,used[j]=used[j-a[i]]+1;

作者:AsadaShino
链接:https://www.acwing.com/solution/content/11075/
*/

4.0 4.0 4.0 分组背包问题

n n n组物品 , , , 每一组至多选择一个物品 ( ( (也可以不选 ) , ), ), 每个物品的体积为 V o l i Vol_i Voli和价值 A r r i , Arr_i, Arri,问容量为 v v v的背包能装下的物品价值总和最大值 . . .

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,v,Dp[1100];
int Cnt[1100],Arr[1100][1100],Vol[1100][1100];
int main()
{
	memset(Dp,0xcf,sizeof(Dp));Dp[0]=0;
	scanf("%d%d",&n,&v);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&Cnt[i]);
		for(int j=1;j<=Cnt[i];j++)
			scanf("%d",&Vol[i][j]);
		for(int j=1;j<=Cnt[i];j++)
			scanf("%d",&Arr[i][j]);
	}
	for(int i=1;i<=n;i++)//阶段 
		for(int j=v;j>=0;j--)//状态 
			for(int k=1;k<=Cnt[i];k++)//决策 
				if(j>=Vol[i][k])
					Dp[j]=max(Dp[j],Dp[j-Vol[i][k]]+Arr[i][k]);
	printf("%d\n",Dp[v]);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值