HDU - 3466

 

传送门

传送门

 

题意:有n件物品,你的钱数是m。每件物品最多买一次,且每件物品除了价格p和价值v外,还有限制q,代表你当前至少有钱数q时,商家才愿意把东西卖给你。求使用不多于m的钱最多获得的价值。

 

题目就容易让人想到01背包,但不同的是,它多了一个条件,导致这道题不满足dp问题的无后效性。那么我们可以考虑先对贪心的决定物品的选择顺序,再利用01背包求解。

首先会想到贪心地优先选择Q值大的物品,反例:

2(n) 6(m)

3(p1) 5(q1)

1(p2) 4(q2)

然后就会想到优先买P值小的物品,因为这样下一步操作有更多的钱,有更好的选择性。还是反例:

2(n) 4(m)

1(p1) 2(q1)

2(p2) 4(q2)

所以我们就会想到优先购买pi-qi最小的物品。假设由于操作顺序的不同,我们能买的物品数量不同。以上面的数据为例,能买一件物品(先买物品一),也可能买两件物品(先买物品二),那么我们有q1+p2 <= m < p1 + q2,移项则有p2-q2<p1-q1,也就是要优先买p-q小的物品。

 

定义dp[i]表示以钱数i最多能买到的物品价值。对数组排序后就是有选择顺序的01背包问题。a[1]存储pi-qi最小的物品。如果我们写的是当前状态是可以由那些状态转移得到(区别于当前状态可以转移到那些状态),那么第一层循环方向应该是N到1的。

或者说从无后效性的角度考虑,即要求每个子问题的决策不能对后面其他未解决的问题产影响,所以我们应当是从大状态转移到小状态(或者理解为当前状态为前面已经更新过的某个状态的子集),就是后面更新的dp[j] = max(dp[j], dp[j - a[i].p] + a[i].v);中的j-a[i].p的状态应当在前面已经更新过了。所以要优先处理出q-p的值小的

 

怎么32行那行判断语句不加也能AC不会越界的,是数据默认了q大于p吗...

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #define INF 0x3f3f3f3f
 6 #define MOD 1000000007
 7 using namespace std;
 8 typedef long long LL;
 9 
10 const int maxn = 5e2 + 10;
11 const int maxm = 5e3 + 10;
12 
13 struct node {
14     int p, q, v;
15 }a[maxn];
16 int dp[maxm];
17 int N, M;
18 
19 bool cmp(struct node& A, struct node& B) {
20     return (A.p - A.q) < (B.p - B.q);
21 }
22 
23 int main(int argc, const char * argv[]) {
24     while (~scanf("%d%d", &N, &M)) {
25         for (int i = 1; i <= N; i++) {
26             scanf("%d%d%d", &a[i].p, &a[i].q, &a[i].v);
27         }
28         sort(a + 1, a + 1 + N, cmp);
29         memset(dp, 0, sizeof(dp));
30         for (int i = N; i >= 1; i--) {
31             for (int j = M; j >= a[i].q; j--) {
32                 if (j < a[i].p) break;//
33                 dp[j] = max(dp[j], dp[j - a[i].p] + a[i].v);
34             }
35         }
36         printf("%d\n", dp[M]);
37     }
38     return 0;
39 }

 

转载于:https://www.cnblogs.com/xFANx/p/7407402.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值