POJ 3624/USACO 2007 DEC: 01背包


——01背包模板题
原题传送门1
原题传送门2

Description

Bessie has gone to the mall’s jewelry store and spies a charm bracelet.
Of course, she’d like to fill it with the best charms possible from the N available charms.
Each charm i in the supplied list has a weight Wi, a ‘desirability’ factor Di ,
and can be used at most once.
Bessie can only support a charm bracelet whose weight is no more than M.
Given that weight limit as a constraint and a list of the charms
with their weights and desirability rating,
deduce the maximum possible sum of ratings.

Data

Input
Input will consist of a series of real numbers no greater than $300.00 each on a separate line. Each
amount will be valid, that is will be a multiple of 5c. The file will be terminated by a line containing
zero (0.00).
Output
Output will consist of a line for each of the amounts in the input, each line consisting of the amount
of money (with two decimal places and right justified in a field of width 6), followed by the number of
ways in which that amount may be made up, right justified in a field of width 17.

	Sample Input
	0.20
	2.00
	0.00
	Sample Output
	0.20 			4	 //近似
	2.00 			293  //近似

1≤N≤3402 1≤M≤12,880 1≤Wi≤400 1≤Di≤100

思路:

好像是 不需要写 的01背包

经典DP背包: 0/1(01)背包

题目描述如下:

给定一个限重W的背包,有一系列物品Ai,各有一重量Wi和价值Vi,要求这些物品要么放要么不放,问不超过限重的情况下,拿到的最大价值是多少.

主要因素

用i表示选到第i个物品(阶段)
用j表示背包的重量(状态)

这样我们的DP就是 dpi j (dp[N][M])了

DP方程

于是对于每个物品Ai ,有选/不选 两种选择

对应地,dp[i][j]=max(dp[i-1]j,dp[i-1][j-W[i]]+Vi)
但是,背包不能为负!
于是,这个状态转移方程就变为:

If j>=W[i] dp[i][j]=max(dp[i-1][j],dp[i-1][j-W[i]]+V[i]))
Else dp[i][j]=dp[i-1][j]

具体问题还需读者自行实现

时空复杂度

时间复杂度

时间复杂度O(NM) 约为 3*107
可以接受不再讨论

空间复杂度

空间复杂度O(NM) 约为 3*107
这个复杂度是无法接受的…
于是,便有

有条件要上,没有条件创造条件也要上。

考虑上面的转移方程,可以发现dp[i-2]的所有状态都是不需要的.
于是,我们抛弃它们覆盖它们.
现在,我们的DP数组就变成dp[2][M] 了 ?
但真的不能再优化了吗?
仔细观察转移方程,发现j状态后面的状态,其实不能影响j
换句话说,j状态只依赖于前面的状态!
所以,我们连i这一维都可以省略,只需在j循环时倒序扫描即可.

Code

// 没有降维(MLE爆空间)
int dp[N][M];
int main()
{
	for (int i=1;i<=n;i++)
		for (int j=0;j<=m;j++)
			if (j>=w[i]) dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
			else dp[i][j]=dp[i-1][j];
	printf("%d\n",dp[n][m]);
}
// 降空间
int dp[2][M];
int main()
{
	for (int i=1;i<=n;i++)
		for (int j=0;j<=m;j++)
			if (j>=w[i]) dp[i&1][j]=max(dp[(i-1)&1][j],dp[(i-1)&1][j-w[i]]+v[i]);
			else dp[i&1][j]=dp[(i-1)&1][j];
	printf("%d\n",dp[n&1][m]);
}
//降维
int dp[M];
int main()
{
	for (int i=1;i<=n;i++)
		for (int j=m;j>=w[i];j--)
			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
	printf("%d\n",dp[m]);
}

感谢奆老关注 qwq ?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值