题意:有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 }