动态规划之01背包(超详解+一学就会)

 一、01背包

定义:

01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn。01背包是背包问题中最简单的问题。01背包的约束条件是给定几种物品,每种物品有且只有一个,并且有权值和体积两个属性。在01背包问题中,因为每种物品只有一个,对于每个物品只需要考虑选与不选两种情况。如果不选择将其放入背包中,则不需要处理。如果选择将其放入背包中,由于不清楚之前放入的物品占据了多大的空间,需要枚举将这个物品放入背包后可能占据背包空间的所有情况。

例题:采药  题目传送门

01背包模板(朴素版本):

#include<bits/stdc++.h>
using namespace std;
const int N = 10000;
int v[N],w[N];
int n,m;
int f[N][N];
int main()
{
	cin>>n>>m;//n为物品个数,m为背包总容量
	for(int i = 1;i<=n;i++) cin>>v[i]>>w[i];//输入题目而定
	for(int i = 1;i<=n;i++)//精华
	{
		for(int j = 0;j<=m;j++)
		{
			f[i][j]=f[i-1][j];
			if(j>=v[i]) f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
		}
	}
	cout<<f[n][m]<<endl;
	return 0;
}

当我们看到题目时,我们要尝试把它转化为背包问题,并且从两个方面考虑:

1.状态表示,f[i][j]代表前i个物品中,体积不超过j的取法的集合(f[i][j]本身代表一个集合)而在f[i][j]中存放的值,则是在fij这个集合中的最大值。

2.状态计算,我们不妨把fij看做一个集合而集合的技术。而状态的计算就是对集合的一个划分。而我们今天讲的是01背包。因此,我们把集合化为选和不选两个部分。因此, fij就是选的部分的最大值和不选的部分的最大值的最大值。 那么,如何计算这两个部分呢 首先,如果不选的话。那么就是把这一个物品去掉,也就是说,在前i-1个物品中。 能够取得的最大值就是不选这个物品的最大价值 如果选的话。那么就相当于先把这个物品去除掉。然后把这个物体的体积也留出一个空来。也就是说,在前i-1个物品里。体积不超过j-v[i]的最大价值,再加上这个物品的价值。就是选这个物品的最大价值。然后综合来看, fij的只就是这两个部分 分别的最大值的,最大值。因此,我们能得到状态转移方程 f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);

01背包优化版本:

#include<bits/stdc++.h>
using namespace std;
const int N = 200000;
int v[N],w[N];
int n,m;
int f[N];//把i维删去
int main()
{
	cin>>n>>m;
	for(int i = 1;i<=n;i++) cin>>v[i]>>w[i];
	for(int i = 1;i<=n;i++)
	{
		//for(int j = v[i];j<=m;j++)//j初始为v[i]是因为避免下面判断
		for(int j = m;j>=v[i];j--)
		{
			//f[j]=max(f[j],f[j-v[i]]+w[i]);实际上这样是错误的,因为我们是从小到大枚举,所以要成
			f[j]=max(f[j],f[j-v[i]]+w[i]);
		}
	}
	cout<<f[m];
	return -1;//heihei
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值