HDU--3466(0-1背包+贪心/后效性)
2015-11-01 12:04
204 查看
题意是: 给你一些钱 m ,然后在这个国家买东西, 共有 n 件物品,每件物品有 价格 P 价值 V 还有一个很特别的属性 Q, Q 指 你如过想买这件物品 你的手中至少有这钱Q 。 虽然你只要花费 钱P ,但你的手中至少有钱Q,如果不足Q ,不能买。问给你钱M ,列出N件物品,最多能获得多少价值的东西。。。。
这道题如果没有Q的限制的话就是一道01背包的水题,但是加上了Q的限制这就是一道考察对DP的深刻理解的题目了,好多题解上说按照p-q从大到小排序即可,但是至于为什么并没有说透,所以今天总结一下。
一个问题无论是DP,还是贪心求解,需要满足一个无后效性,其中所谓的无后效性是指:“下一时刻的状态只与当前状态有关,而和当前状态之前的状态无关,当前的状态是对以往决策的总结”。就是说我在当前状态做转移的时候,前面的所有的状态都已经枚举过了,只不过只保留下来了最优解,但是抵达当前状态路径不唯一,仅是最终最优结果唯一。
不考虑q的限制的01背包的状态转移方程是d[j] = max(d[j],d[j--p[i]]+v[i]);显然j状态实际上是从d[i-1][j]和d[i-1][j-p[i]]转移过来的。(这里我用了滚动数组)那么什么时候可以转移呢?j-p[i]是这个状态的花费,那么m-(j-p[i])是当前我所剩下的钱,只有当m-(j-p[i]) > q[i]的时候,才能转移.
整理一下就p[i] <= j <=m+ p[i] - q[i];即可以更新的区间是(p[i],m+q[i] - p[i])所谓无后效性是指,前面的在更新时对后面的决策无影响。那么后面的d[j-p[i]]这个状态肯定在前面已经更新到了。所以就是说前面的更新的范围应该比后面大。所以就是p1 - q1 > p2-q2;即按照p-q从大到小排序,或者q - p按照从小到大排序才能保证后面的能更新到不丢失状态。
AC代码:
这道题如果没有Q的限制的话就是一道01背包的水题,但是加上了Q的限制这就是一道考察对DP的深刻理解的题目了,好多题解上说按照p-q从大到小排序即可,但是至于为什么并没有说透,所以今天总结一下。
一个问题无论是DP,还是贪心求解,需要满足一个无后效性,其中所谓的无后效性是指:“下一时刻的状态只与当前状态有关,而和当前状态之前的状态无关,当前的状态是对以往决策的总结”。就是说我在当前状态做转移的时候,前面的所有的状态都已经枚举过了,只不过只保留下来了最优解,但是抵达当前状态路径不唯一,仅是最终最优结果唯一。
不考虑q的限制的01背包的状态转移方程是d[j] = max(d[j],d[j--p[i]]+v[i]);显然j状态实际上是从d[i-1][j]和d[i-1][j-p[i]]转移过来的。(这里我用了滚动数组)那么什么时候可以转移呢?j-p[i]是这个状态的花费,那么m-(j-p[i])是当前我所剩下的钱,只有当m-(j-p[i]) > q[i]的时候,才能转移.
整理一下就p[i] <= j <=m+ p[i] - q[i];即可以更新的区间是(p[i],m+q[i] - p[i])所谓无后效性是指,前面的在更新时对后面的决策无影响。那么后面的d[j-p[i]]这个状态肯定在前面已经更新到了。所以就是说前面的更新的范围应该比后面大。所以就是p1 - q1 > p2-q2;即按照p-q从大到小排序,或者q - p按照从小到大排序才能保证后面的能更新到不丢失状态。
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> #include <queue> #include <stack> #define N 100005 #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define lc rt<<1 #define rc rt<<1|1 #define INF 0x3f3f3f3f using namespace std; const int maxn = 5005; const int mod = 1000000007; typedef long long ll; int n,m; struct node { int p,q,v; bool operator < (const node& r)const { return q - p < r.q - r.p; } }a[maxn]; int d[maxn]; int main() { //freopen("in","r",stdin); while(~scanf("%d%d",&n,&m)) { for(int i = 1; i <= n; ++i) { scanf("%d%d%d",&a[i].p, &a[i].q,&a[i].v); } sort(a+1,a+n+1); memset(d,0,sizeof(d)); int mx = 0; for(int i = 1; i <= n; ++i) { for(int j = m; j >= a[i].q; --j) { d[j] = max(d[j],d[j - a[i].p] + a[i].v); } } printf("%d\n",d[m]); } }
相关文章推荐
- 【鸟哥的linux私房菜-学习笔记】Bash shell之管线命令
- ThinkPHP3.2.3中典型的ajax获取json数据方法
- codeforces #328 C. The Big Race
- 如何做到一个分数序列和
- python os目录和文件相关操作
- Coursera_Stanford_ML_ex7_K-means and PCA 作业记录
- 常见 门户布局
- JAVA基础1-JAVA入门和JDK的安装与配置
- 四校联训Round8心得体会
- SQLServer的数据类型
- Spring Spring mvc mybatis集成
- VisualStudio报错This function or variable may be unsafe的解决方法
- ios完整学习路线
- 稳扎稳打,踏实前进
- Codeforces Round #328 (Div. 2) A PawnChess
- 期中总结
- 统计句子中的不同单词个数(句子中含有标点符号,单词不区分大小写)
- NSApp openURL 坑人
- 使用gradle编译和运行Java程序
- JAVA设计模式-2-创建型模式