博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
杭电3466————DP之01背包(对状态转移方程的更新理解)
阅读量:4677 次
发布时间:2019-06-09

本文共 4200 字,大约阅读时间需要 14 分钟。

Proud Merchants

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 2455    Accepted Submission(s): 1007


Problem Description
Recently, iSea went to an ancient country. For such a long time, it was the most wealthy and powerful kingdom in the world. As a result, the people in this country are still very proud even if their nation hasn’t been so wealthy any more.
The merchants were the most typical, each of them only sold exactly one item, the price was Pi, but they would refuse to make a trade with you if your money were less than Qi, and iSea evaluated every item a value Vi.
If he had M units of money, what’s the maximum value iSea could get?
 

Input
There are several test cases in the input.
Each test case begin with two integers N, M (1 ≤ N ≤ 500, 1 ≤ M ≤ 5000), indicating the items’ number and the initial money.
Then N lines follow, each line contains three numbers Pi, Qi and Vi (1 ≤ Pi ≤ Qi ≤ 100, 1 ≤ Vi ≤ 1000), their meaning is in the description.
The input terminates by end of file marker.
 

Output
For each test case, output one integer, indicating maximum value iSea could get.
 

Sample Input
 
2 10 10 15 10 5 10 5 3 10 5 10 5 3 5 6 2 7 3
 

Sample Output
 
5 11
开始的时候没多想,以为这个题目很简单,于是写下了这样的代码
#include 
#include
#include
#define maxn 5005using namespace std;struct Goods{ int value; int price; int minmoney;/*低于该价格不售出*/ /*且minmoney >= price*/ };/*商品:goods*/ int dp[maxn];/*dp[i]表示i元钱能购买的最大价值*/ struct Goods goods[5005];int cmp(struct Goods a,struct Goods b){ return a.minmoney < b.minmoney ;}int main(){ int n,totalmoney; while(scanf("%d%d",&n,&totalmoney) != EOF) { memset(dp,0,sizeof(dp)); memset(goods,0,sizeof(goods)); for(int i = 0 ; i < n ; i++) scanf("%d%d%d",&goods[i].price,&goods[i].minmoney,&goods[i].value); sort(goods,goods+n,cmp); for(int i = 0 ; i < n ; i ++) for(int j = totalmoney ; j >= goods[i].minmoney ; j--) dp[j] = max(dp[j],dp[j-goods[i].price] + goods[i].value); printf("%d\n",dp[totalmoney]); } return 0;}
样例测试一下没问题,但是不断WA,说实在的我不明白到底哪里错了。
思路很简单,想把goods[i]按照minmoney从小到大的顺序排列,尽量把minmoney小的先买了(放入背包)。
之后看了一下别人的题解,发现了自己逻辑上的错误。
比如说按照我的想法,举一个反例。
项目 price minmoney value
物品1  10 20 X
物品2 99 100 Y
       
按照之前的想法是先对物品3进行取舍。
如果
先对物品1取舍  
物品2应当借助之前的状态(也就是购买了物品1或者不购买物品1之后的totalmoney的值)进行状态转移.但是如果物品2的minmoney过大的话,整个从goods[2].minmoney (即100) 到 totalmoney的这一区间内的所有的状态都没有了。但是如果先对物品2进行取舍的话,因为物品1的minmoney的值并不大,更有可能产生从goods[1].minmoney 到 totalmoney的状态.
从动规方程是可以看出,当前状态是由之前的状态决定的。所以之前状态的选择一到要有后效性(即能尽可能的影响到后边的状态)
事实上:
先选择物品1,能影响到的状态区间是[ goods[1].price + goods[2].minmoney , totalmoney ]
/*选择了物品1就花费了goods[1].price,然后你至少还需要goods[2].minmoney的钱才能选择物品2,这两者的和就是你想要尽可能多的影响后边的状态所需要的最少金钱*/
先选择物品2,能影响到的状态区间是[ goods[2].price + goods[1].minmoney , totalmoeny ]
/*选择了物品1就花费了goods[2].price,然后你至少还需要goods[1].minmoney的钱才能选择物品1,这两者的和就是你想要尽可能多的影响后边的状态所需要的最少金钱*/
到底先选择哪一个呢?我们想尽可能多的影响后边的状态,自然让区间的下限尽可能的小。
即:
假如先选择第i件物品,在选择第j件物品,那么:
(goods[i].price + goods[j].minmoney) < (goods[j].price + goods[i].minmoney)
也即
goods[i].minmoney - goods[i].price > goods[j].minmoney - goods[j].price
所以就按照(goods[i].minmoney - goods[i].price)由大到小的顺序将其排序后直接成为简单的01背包即可
(亲测31MS正确)
#include 
#include
#include
#define maxn 5005using namespace std;struct Goods{ int value; int price; int minmoney;/*低于该价格不售出*/ /*且minmoney >= price*/ };/*商品:goods*/ int dp[maxn];/*dp[i]表示i元钱能购买的最大价值*/ struct Goods goods[5005];int cmp(struct Goods a,struct Goods b){ return a.minmoney - a.minmoney < b.minmoney - b.minmoney ;}int main(){ int n,totalmoney; while(scanf("%d%d",&n,&totalmoney) != EOF) { memset(dp,0,sizeof(dp)); memset(goods,0,sizeof(goods)); for(int i = 0 ; i < n ; i++) scanf("%d%d%d",&goods[i].price,&goods[i].minmoney,&goods[i].value); sort(goods,goods+n,cmp); for(int i = 0 ; i < n ; i ++) for(int j = totalmoney ; j >= goods[i].minmoney ; j--) dp[j] = max(dp[j],dp[j-goods[i].price] + goods[i].value); printf("%d\n",dp[totalmoney]); } return 0;}

转载于:https://www.cnblogs.com/sixdaycoder/p/4348398.html

你可能感兴趣的文章
java有date类型吗_关于java中date类型的问题
查看>>
java中svg图片怎么用_svg如何使用
查看>>
java dart 官司_From Java to Dart
查看>>
java ftp 读取excel_从Excel文件读取数据表
查看>>
oracle 有哪些字典表,oracle 常用字典表
查看>>
linux c多进程多线程,linux下的C\C++多进程多线程编程简易例子
查看>>
linux 命令 考试,linux常用命令总结-第一次考试
查看>>
linux动态库编译多重依赖,Linux动态库多重依赖
查看>>
linux网卡缓冲区设置,【Linux】tcp缓冲区大小的默认值、最大值
查看>>
opus编译linux,Linux 下源码编译FFMEG
查看>>
linux 运行real basic,REALbasic 快速入门.pdf
查看>>
linux启动tomcat不停的触发gc,tomcat启动时就频繁gc和full gc
查看>>
linux uart串口驱动,X-017-KERNEL-串口驱动开发之uart driver框架
查看>>
linux 添加串口数量,如何在Linux中添加4个以上的串口设备?
查看>>
关于sqoop导入数据的时候添加--split-by配置项对sqoop的导入速度的影响。
查看>>
nginx配置
查看>>
2014-11-9------- 设有一数据库,包括四个表:学生表(Student)、课程表(Course)、成绩表(Score)以及教师信息表(Teacher)。...
查看>>
python 魔法方法补充(__setattr__,__getattr__,__getattribute__)
查看>>
NOIP 2010 关押罪犯
查看>>
CentOS7.5删除旧的内核
查看>>