HDU 3466 (排序消除后效性的01背包) Proud Merchants

题意:

你有m块钱,有n件商品,每件商品有它的价格p 要买这件商品至少拥有的钱数q和价值w,问能获得的最大价值是多少

分析:

商品如果没有属性q的话就是一个单纯的01背包,正是因为该属性,如果再像01背包那样求解的话就有了后效性,因为很可能存在这种情况:

先买物品1就买不了物品2,但是如果先买物品2就可以继续买物品1

下面我们来找一下出现这种情况的条件是什么:

假设现在又两件物品1和2,你手中有k块钱,而且如果先买1的话能买2,但是先买2的话不能买1,则有:

p1 + q2 ≤ k  < p2 + q1  

移项得,q1 - p1 > q2 - p2

 

好的,如果两件商品满足q1 - p1 > q2 - p2,那么一定存在一个或多个k值满足 p1 + q2 ≤ k  < p2 + q1 ,所以我们在考虑买物品的时候一定要考虑 q减p 的值大的

 

可是如果你按照q-p从大到小排序的话,就又错了,囧rz

下面我来照搬一下别人博客上的话:

通俗的说: 这个dp过程 正好是逆向的  。   dp[c-p[i]]是dp[c]的最优子结构。

        所以 在DP 的时候我们应该按照 M的值从小到大排序。

我还不能理解太多,但我找了个例子试了一下,真的是这样的

比如,你有13块钱,p1 = 5,q1 = 11,w1 = 3,p2 = 3,q2 = 8,w2 = 4

按照错误方式排序:

按照正确方式排序:

这的好神奇,不能理解更多。。

 

 1 //#define LOCAL
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 using namespace std;
 6 
 7 const int maxn = 5000 + 10;
 8 
 9 struct Trade
10 {
11     int p, q, w;
12     bool operator< (const Trade& rhs) const
13     {
14         return (q - p) < (rhs.q - rhs.p);
15     }
16 }trades[maxn];
17 int n, m, dp[maxn];
18 
19 int main(void)
20 {
21     #ifdef LOCAL
22         freopen("3466in.txt", "r", stdin);
23     #endif
24 
25     while(scanf("%d%d", &n, &m) == 2)
26     {
27         memset(dp, 0, sizeof(dp));
28         for(int i = 1; i <= n; ++i)
29             scanf("%d%d%d", &trades[i].p, &trades[i].q, &trades[i].w);
30         sort(trades + 1, trades + 1 + n);
31         for(int i = 1; i <= n; ++i)
32             for(int j = m; j >= trades[i].q; --j)
33                 dp[j] = max(dp[j], dp[j - trades[i].p] + trades[i].w); 
34         printf("%d\n", dp[m]);
35     }
36     return 0;
37 }
代码君

 

posted @ 2014-09-04 08:34  AOQNRMGYXLMV  阅读(214)  评论(0)    收藏  举报