poj 1276 Cash Machine 多重背包
2016-07-13 13:07
417 查看
传送门:poj 1276 Cash Machine
输入的前两个数表示背包容量,第二个数字表示有N种货币
接下来的N组两个数。第一个数表示货币数量,第二个数表示货币的价值
输出最接近并且小于等于背包容量的价值。
状态转移方程为:
看到这方程中有三个变量,最普遍的思想就是三层循环依次遍历i,j,k。但是这种如果数据的范围过大的时候就很容易超时了。
我们一般会采用一种方法就是
题目大意
有各种不同面值的货币,每种面值的货币有不同的数量,请找出利用这些货币可以凑成的最接近且小于等于给定的数字cash的金额。输入的前两个数表示背包容量,第二个数字表示有N种货币
接下来的N组两个数。第一个数表示货币数量,第二个数表示货币的价值
输出最接近并且小于等于背包容量的价值。
解题思路
在理解的01背包的基础上,完全背包,指每个物品有无限多个。
多重背包,指每个物品的数量是有限的。当然,这时的问题不再是拿与不拿,而是拿多少的问题,当然不能超过背包容量。
状态转移方程为:
dp( i,j ) = Max( dp( i-1, j ), dp( i-1, j-k*w[i]) + k*v[i] ) ( 0 <= k <= c/ w[i] ).
看到这方程中有三个变量,最普遍的思想就是三层循环依次遍历i,j,k。但是这种如果数据的范围过大的时候就很容易超时了。
我们一般会采用一种方法就是
二进制压缩。将原来的物品按照2的n次方进行重新组合。用1、2、4、8…进行组合,可以组合出任意的数字。
AC代码
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int main() { int n,amount; int num,deno; int dp[100005]; int value[100005]; while(scanf("%d%d",&amount,&n)!=EOF) { int cnt = 1; memset(dp,0,sizeof dp); for(int i=1;i<=n;i++) { scanf("%d%d",&num,&deno); for(int j=1;j<=num;j*=2)//二进制压缩 { value[cnt++] = j*deno; num-=j; } if(num>0) value[cnt++] = num * deno; } //如果不懂画一个二维表就差不多能懂了 for(int i=1;i<cnt;i++) { for(int j = amount;j>=value[i];j--) dp[j] = max(dp[j],dp[j-value[i]]+value[i]); } printf("%d\n",dp[amount]); } return 0; }
相关文章推荐
- TFDS中检测算法的应用
- SpringMVC访问静态资源的三种方式
- Git10--分支管理
- form表单提交数据编码方式和tomcat接受数据解码方式的思考
- openstack安装过程中软件包缺失
- QT工程构建一般环境
- centos7 安装 mariadb(mysql的一个分支) 的正确命令
- Git9--从远程库克隆
- Hdu4497 GCD and LCM 素数筛法+分解质因数
- Ambari服务依赖关系图生成脚本
- pagerank
- caffe BasePrefetchingDataLayer 学习
- 查询数据库每张表记录条数
- django crsf not set问题
- “暑假”学习开学典礼
- 关于苹果手机的真机调试
- UI开发学习指南
- PHP通用分页(Pager)类
- MVC学习 (一)
- 转载 asp.net中ViewState的用法详解