动态规划(01背包问题)

背包问题在dp问题中占很大的比重,很多dp问题都可以抽象成背包问题来解决,那么什么是背包问题呢?

我的理解是:给你两个元素和两种元素的状态,让我们求在某个元素在限制条件下达到某种状态的最佳方案;

具体到背包问题中就是给你每种物品的体积和价值,让我们求解在某个给定的体积下,你能装入的最大价值物品是多少。

在次引入ACwing的背包题目:2. 01背包问题 - AcWing题库icon-default.png?t=M276https://www.acwing.com/problem/content/2/

01背包问题是最简单的背包问题,因为每种物品只有选与不选的区别,所以每种物品我们可以认为有两种状态:选他,或者不选他;

动态规划(dp)问题有点像贪心问题,我们都是在找此状态下的最优解;

01背包问题的分析有两个方面,1是状态的表示,2是状态的计算;01背包问题中,我们有最简单的一维数组解法,但是在这里我们先给出二维数组的解法:

存储初始数据时,我们用v数组存储体积,用w数组存储价值(可以是价格也可以是重量)

状态的表示我们采用二维数组的横纵坐标,横坐标表示取前i种物品,纵坐标j表示容积。那么合起来,我们二维数组g[i][j]表示的就是:只取用前i种物品的情况下,容积为j时我们的最优解是多少?于是我们就用二维数组完美模拟出了状态;

状态的计算我们分为两部分,其一是我们选择第i捡物品,其二是不选择;因为我们的物品只有一个,所以可以理所当然的分出这两种状态,那么该如何计算呢?

 

 我们用这个图来看一下:选择两种计算的条件是我们当前的容积是否大于第i件物品的容积,如果大于的话,我们就可以选择是否拿第i件物品,拿的话,就是剩余j-v[i]的体积中,我们再找到一个最优解加上第i件物品的重量,看看是不是比我们不拿第i件物品的价值更高,取最大值即可;

如果当前的容积都没有比第i件物品大,我们就只能选择不拿第i件物品,相当于我们这个时候就变成了取前i-1件物品是的最优解;于是我们顺理成章的可以把第i-1的状态传递下来;

经过所有物品的循环,我们能做到这样一件事:只取前i件物品的情况下,我取得一定是最优解!

图示:

 最后我们直接输出答案即可,注意,i为零的情况是代表不取物品,当前体积下的最优解,一定都为零,所以不做处理即可;

代码如下:

 

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=1010;
int g[N][N];//主要部分,用来计算 
int v[N],w[N];//v存储体积,w存储价值 

int main()
{
	int n,m;
	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=0;j<=m;j++)
		{
			g[i][j]=g[i-1][j];//无论我们是否取第i件物品,这个继承要有 
			if(j>=v[i])//特判,如果可以取第i件物品,我们就会在两种选择中取其最优解 
			g[i][j]=max(g[i-1][j],g[i-1][j-v[i]]+w[i]);
		}
	}
	
	cout<<g[n][m]; 
}

总的来说,由于我们的循环是从取一件物品开始,每一层我们都能得到最优解,所以即使后面我们用到了前一层的状态,得到的也一定是最优解;

到此完毕

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值