01背包问题

关于01背包问题的三种DP模式

题目模型:
有n个重量和价值分别为wi,vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。
限制条件
n∈[1,100],
wi,vi∈[1,100],
W∈[1,10000].

输入

n = 4
(wi,vi) = {(2,3), (1,2), (3,4), (2,2)}
W = 5

输出

7(选择第0、1、3号物品)

本题我们不写递归函数,直接利用递推式将各项的值算出来,二重循环解决。
通过使用DP数组,我们可以完成所有结果的存取。

DP方法一:
我们记dp[i][j]为 从第i个物品开始挑选总重小于j时,总价值最大值。实现dp的代码如下:

void solve1()
{//从第i个物品开始挑选总重小于j时,总价值最大值为dp[i][j]
	for (int i = n - 1; i >= 0; i--)
	{//i从最后一项开始计算
		for (int j = 0; j <= W; j++)
		{
			if (j < w[i])
			{//第i个物品重量超重,跳过i,从i+1开始递归
				dp[i][j] = dp[i + 1][j];
			}
			else
			{//第i个物品不超重,挑选或不挑选,比较两者最大值存入dp
				dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i]);
			}
		}
	}
	cout << dp[0][W];//输出结果
}

DP方法二:
我们记dp[i+1][j]为 从0~i这i+1个物品中选出总重量不超过j的物品时总价值的最大值。实现dp的代码如下:

void solve2()
{//从0~i这i+1个物品中选出总重量不超过j的物品时总价值最大值为dp[i+1][j]
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j <= W; j++)
		{
			if (j < w[i])
			{//超重说明当前第i个物品选不了
			 //状态转移为:从0~i-1这i个物品中选出总重量不超过j的物品时
			 //总价值最大值 == 从0~i这i+1个物品中选出总重量不超过j的
		     //物品时总价值最大值
				dp[i + 1][j] = dp[i][j];
			}
			else
			{//选i不选i比较一下
				dp[i + 1][j] = max(dp[i][j], dp[i][j - w[i]] + v[i]);
			}
		}
	}
	cout << dp[n][W];//输出结果
}

DP方法三:
我们记dp[i][j]为 从前i个物品中选取总重不超过j的物品时总价值的最大值。实现的代码如下:

void solve3()
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j <= W; j++)
		{
			dp[i + 1][j] = max(dp[i + 1][j], dp[i][j]);
			//先在前i个物品和前i+1个物品前考虑一下最大值
			if (j + w[i] <= W)
			{
				dp[i + 1][j + w[i]] = max(dp[i + 1][j + w[i]], dp[i][j] + v[i]);
				//前i+1个(不包括i+1)物品中选取总重不超过j+w[i]时,所对应最大值
				//应当为:选取了第i个物品 或 不选取第i个物品
				//两种情况下的最大值
			}
		}
	}
	cout << dp[n][W];//输出结果
}

第三种DP的状态转移为:从前i个物品中选取总重不超过j时的状态
转移至 前i+1个物品中选取总重不超过j前i+1个物品中选取总重不超过j+w[i]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值