POJ 3260 The Fewest Coins(多重背包+全然背包)

http://poj.org/problem?id=3260

题意:

John要去买价值为m的商品. 如今的货币系统有n种货币,相应面值为val[1],val[2]…val[n]. 然后他身上每种货币有num[i]个. John必须付给售货员>=m的金钱, 然后售货员会用最少的货币数量找钱给John.

问你John的交易过程中, 他给售货员的货币数目+售货员找钱给他的货币数目 的和最小值是多少?

分析:

本题与POJ 1252类型:

http://blog.csdn.net/u013480600/article/details/40454963

如果John付款总额为S时的货币数目为T1, 售货员找钱 (S-m) 的货币数目为T2. 我们要使得T1+T2最小, 那么自然T1和T2也必须分别是最小的(即T1是当John付款正好S时,最少须要多少张货币.
T2是当售货员正好找钱S-m时,最少须要多少张货币.).

John给的钱肯定>=m, 可是究竟最大多大呢? 假设我们直接求John的全部金钱总和, 然后再DP, 肯定超时. 这个up_bound (即john最多给售货员的钱数) 能够简单设置一个大数值就可以. 网上有个证明(这个证明我也有点不明确):

John的付款数最多为maxv*maxv+m

证明例如以下:

假设John的付款数大于了maxv*maxv+m,即付硬币的数目大于了maxv,依据鸽笼原理。至少有两个的和对maxv取模的值相等(这个意思应该是:至少maxv+1个硬币对maxv求余,然后余数属于[0,maxv-1]范围,肯定有至少两个硬币的余数同样的),也就是说。这部分硬币可以用更少的maxv来取代(这句话我不理解)。

证毕。

第一个问题是一个多重背包问题.

令dp[i][j]==x 表示当John用前i种货币组成j元钱时, 最少须要x张货币.

初始化: dp全为INF(无穷大), 且dp[0][0]=0.

对于每种货币, 我们分情况对它进行处理:

1.    假设val[i]*num[i]>=up_bound时, 做一次全然背包.

2.    假设val[i]*num[i]<up_bound时, 做多次01背包.

终于所求: dp[n][i] 当中i属于[m, up_bound].

第2个问题是一个全然背包问题.

令dp2[i][j]==x 表示售货员用前i种硬币组成j元钱时, 最少须要x张货币.

初始化: dp2全为INF(无穷大), 且dp2[0][0]=0.

状态转移: dp2[i][j] = max( dp2[i-1][j] , dp2[i][j-val[i]]+1 )

终于所求: dp2[n][i] 当中i属于[m, up_bound].

终于合并问题1和问题2的解, 我们枚举i从m到up_bound, 找出dp[i]+dp2[i-m]的最小值就可以.

AC代码:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. #define INF 1e9
  6.  
  7. int n;//n种硬币
  8. int m;//购买商品的价值
  9. int up_bound;//DP价值上界
  10. int val[100+5];//每种硬币价值
  11. int num[100+5];//每种硬币数目
  12. int dp[55555]; //多重背包
  13. int dp2[55555];//全然背包
  14.  
  15. //1次01背包
  16. void ZERO_ONE_PACK(int *dp,int cost,int sum)
  17. {
  18. for(int i=up_bound;i>=cost;i--)
  19. dp[i] = min(dp[i], dp[i-cost]+sum);//注意这里是+sum
  20. }
  21.  
  22. //1次全然背包
  23. void COMPLETE_PACK(int *dp,int cost)
  24. {
  25. for(int i=cost;i<=up_bound;i++)
  26. dp[i] = min(dp[i], dp[i-cost]+1);
  27. }
  28.  
  29. //1次多重背包
  30. void MULTIPLY_PACK(int *dp,int cost,int sum)
  31. {
  32. if(cost*sum>=up_bound)
  33. {
  34. COMPLETE_PACK(dp,cost);
  35. return ;
  36. }
  37.  
  38. int k=1;
  39. while(k<sum)
  40. {
  41. ZERO_ONE_PACK(dp,cost*k,k);
  42. sum -=k;
  43. k *=2;
  44. }
  45. ZERO_ONE_PACK(dp,cost*sum,sum);
  46.  
  47. }
  48.  
  49. int main()
  50. {
  51. while(scanf("%d%d",&n,&m)==2)
  52. {
  53. //读取输入+计算上界
  54. int max_val=0;
  55. for(int i=1;i<=n;i++)
  56. {
  57. scanf("%d",&val[i]);
  58. max_val= max(max_val,val[i]);
  59. }
  60. for(int i=1;i<=n;i++)
  61. scanf("%d",&num[i]);
  62. up_bound=max_val*max_val+m;//上界
  63.  
  64. //初始化dp和dp2
  65. for(int i=1;i<=up_bound;i++)
  66. dp[i]=dp2[i]=INF;
  67. dp[0]=dp2[0]=0;
  68.  
  69. //递推过程
  70. for(int i=1;i<=n;i++)
  71. {
  72. MULTIPLY_PACK(dp,val[i],num[i]);
  73. COMPLETE_PACK(dp2,val[i]);
  74. }
  75.  
  76. //统计结果
  77. int ans=INF;
  78. for(int i=m;i<=up_bound;i++)
  79. ans= min(ans, dp[i]+dp2[i-m]);
  80. printf("%d\n",ans==INF?-1:ans);
  81. }
  82. return 0;
  83. }

POJ 3260 The Fewest Coins(多重背包+全然背包)的更多相关文章

  1. POJ 3260 The Fewest Coins(多重背包问题, 找零问题, 二次DP)

    Q: 既是多重背包, 还是找零问题, 怎么处理? A: 题意理解有误, 店主支付的硬币没有限制, 不占额度, 所以此题不比 1252 难多少 Description Farmer John has g ...

  2. POJ 3260 The Fewest Coins(完全背包+多重背包=混合背包)

    题目代号:POJ 3260 题目链接:http://poj.org/problem?id=3260 The Fewest Coins Time Limit: 2000MS Memory Limit: ...

  3. POJ 3260 The Fewest Coins 最少硬币个数(完全背包+多重背包,混合型)

    题意:FJ身上有各种硬币,但是要买m元的东西,想用最少的硬币个数去买,且找回的硬币数量也是最少(老板会按照最少的量自动找钱),即掏出的硬币和收到的硬币个数最少. 思路:老板会自动找钱,且按最少的找,硬 ...

  4. POJ 3260 The Fewest Coins(背包问题)

    [题目链接] http://poj.org/problem?id=3260 [题目大意] 给出你拥有的货币种类和每种的数量,商店拥有的货币数量是无限的, 问你买一个价值为m的物品,最少的货币流通数量为 ...

  5. poj 3260 The Fewest Coins

    // 转载自http://blog.163.com/benz_/blog/static/18684203020115721917109/算法不难看出,就是一个无限背包+多重背包.问题在于背包的范围.设 ...

  6. HDU 3591 The trouble of Xiaoqian(多重背包+全然背包)

    HDU 3591 The trouble of Xiaoqian(多重背包+全然背包) pid=3591">http://acm.hdu.edu.cn/showproblem.php? ...

  7. POJ3260——The Fewest Coins(多重背包+完全背包)

    The Fewest Coins DescriptionFarmer John has gone to town to buy some farm supplies. Being a very eff ...

  8. hdu3591The trouble of Xiaoqian 多重背包+全然背包

    //给出Xiaoqian的钱币的价值和其身上有的每种钱的个数 //商家的每种钱的个数是无穷,xiaoqian一次最多付20000 //问如何付钱交易中钱币的个数最少 //Xiaoqian是多重背包 / ...

  9. DP专题·三(01背包+完全背包)

    1.hdu 2126 Buy the souvenirs 题意:给出若干个纪念品的价格,求在能购买的纪念品的数目最大的情况下的购买方案. 思路:01背包+记录方案. #include<iostr ...

随机推荐

  1. SQL函数解释(待补)

    1.SQL— CONCAT(字符串连接函数) 有的时候,我们有需要将由不同栏位获得的资料串连在一起.每一种资料库都有提供方法来达到这个目的: MySQL: CONCAT() Oracle: CONCA ...

  2. Spring Boot . 4 -- 定制 Spring Boot 配置

    覆写 Auto-Configuration 的类 利用外部属性进行动态配置 [本文] 定制 Error 页面 [第二篇] Spring Boot的自动配置可以节省很多无趣的配置工作,但是并不是所有的自 ...

  3. [Python3网络爬虫开发实战] 1.9.5-Scrapyrt的安装

    Scrapyrt为Scrapy提供了一个调度的HTTP接口,有了它,我们就不需要再执行Scrapy命令而是通过请求一个HTTP接口来调度Scrapy任务了.Scrapyrt比Scrapyd更轻量,如果 ...

  4. JAVA加载Properties配置资源文件

    JAVA加载Properties配置资源文件 制作人:全心全意 配置文件(资源文件):以properties作为拓展名的文件 Java代码是如何加载properties文件的? 必须使用Propert ...

  5. assert.notEqual()

    浅测试,使用不等于比较运算符(!=)比较. const assert = require('assert'); assert.notEqual(1, 2); // OK assert.notEqual ...

  6. 经典卷积网络VGG,GoodLeNet,Inception

    目录 ImageNet LeNet-5 LeNet-5 Demo AlexNet VGG 1*1 Convolution GoogLeNet Stack more layers? ImageNet L ...

  7. Python之面向对象slots与迭代器协议

    Python之面向对象slots与迭代器协议 slots: # class People: # x=1 # def __init__(self,name): # self.name=name # de ...

  8. Poj 1106 Transmitters

    Poj 1106 Transmitters 传送门 给出一个半圆,可以任意旋转,问这个半圆能够覆盖的最多点数. 我们枚举每一个点作为必然覆盖点,那么使用叉积看极角关系即可判断其余的点是否能够与其存在一 ...

  9. Python使用selenium实现网页用户名 密码 验证码自动登录功能

    一.安装selenium 二.下载谷歌浏览器驱动 1.去http://chromedriver.storage.googleapis.com/index.html下载chromedriver.exe( ...

  10. source insight中的快捷键总结

    1.快捷键 1,Shift+F8高亮显示指定字符. 2,Ctrl+F找出来的结果用F4,F3前进后退查找. 3,Alt+,后退alt+.前进查找关键字. 4,Alt+G或者F5跳转到某个固定的行号. ...