POJ 3466 带限制的 0 1背包问题

POJ 3466 带限制的 0 1背包问题

题目链接

分析如下:

由于必须要 超过 q 值才能购买,而无论是一维还是二维普通 0 0 0 1 1 1 背包问题,它后一个的值都需要用到上一个的值。
比如:
我们现在更新 d p [ i ] [ j ] dp[i][j] dp[i][j],需要用到 d p [ i − 1 ] [ j − w [ i ] ] + v [ i ] dp[i-1][j-w[i]]+v[i] dp[i1][jw[i]]+v[i] 的值,但是必须满足的是,当前 j j j 要大于给定的 q [ i ] q[i] q[i]才能转移,所以如果以 d p [ i − 1 ] [ j − w [ i ] ] + v [ i ] dp[i-1][j-w[i]]+v[i] dp[i1][jw[i]]+v[i] 来更新 d p [ i ] [ j ] dp[i][j] dp[i][j] 的话,那么 j 必须要 大于等于 p 才可以。
那么更新 d p [ i ] [ j ] dp[i][j] dp[i][j] ,我需要的是 d p [ i − 1 ] [ p 2 − w [ i ] ] + v [ i ] 到 d p [ i − 1 ] [ V − w [ i ] ] + v [ i ] ① dp[i-1][p2-w[i]]+v[i] 到 dp[i-1][V-w[i]]+v[i] ① dp[i1][p2w[i]]+v[i]dp[i1][Vw[i]]+v[i] 的值。( P 2 P2 P2 指的是 第 i i i 物品的 p p p 值)
而对于第 i − 1 i-1 i1 的物品,我只有当 j > = p 1 j>=p1 j>=p1 的时候, d p [ i − 1 ] [ j − w [ i ] ] + v [ i ] ② dp[i-1][j-w[i]]+v[i]② dp[i1][jw[i]]+v[i] 才更新,即我只更新了 d p [ i − 1 ] [ p 1 − w [ i ] ] + v [ i ] 到 d p [ i − 1 ] [ V − w [ i ] ] + v [ i ] dp[i-1][p1-w[i]]+v[i] 到 dp[i-1][V-w[i]]+v[i] dp[i1][p1w[i]]+v[i]dp[i1][Vw[i]]+v[i]的值。
所以如果我要更新 d p [ i ] [ j ] dp[i][j] dp[i][j],那么必须要使得 ② ② 的范围包含 ① ① 的范围,故需要 p 1 − q 1 > p 2 − q 2 p1-q1>p2-q2 p1q1>p2q2 ,所以进行 D P DP DP之前,需要先以 ( p − q ) (p-q) pq降序排列,再进行 普通 01 0 1 01 背包即可。

代码如下:

#include<iostream>
#include<algorithm>
#include<string.h>
#define MAXN 508
using namespace std;
int n, m;
int dp[5008];
struct Node
{
	int p;
	int q;
	int v;
}A[MAXN];
bool cmp(const Node a, const Node b) {
	return a.q - a.p < b.q - b.p;
}
int main()
{
	while (~scanf_s("%d%d", &n, &m))
	{
		for (int i = 1; i <= n; i++) {
			scanf_s("%d%d%d", &A[i].p, &A[i].q, &A[i].v);
		}
		memset(dp, 0, sizeof(dp));
		sort(A + 1, A + n + 1, cmp);
		for (int i = 1; i <= n; i++) {
			for (int j = m; j >= A[i].q; j--) {
				dp[j] = max(dp[j], dp[j - A[i].p] + A[i].v);
			}
		}
		printf("%d\n", dp[m]);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值