POJ 1252 Euro Efficiency(完全背包, 找零问题, 二次DP)
Description
A student buying a 68 guilder book before January 1st could pay for the book with one 50 guilder banknote and two 10 guilder banknotes, receiving two guilders in change. In short:50+10+10-1-1=68. Other ways of paying were: 50+25-5-1-1, or 100-25-5-1-1.Either way, there are always 5 units (banknotes or coins) involved in the payment process, and it
could not be done with less than 5 units.
Buying a 68 Euro book is easier these days: 50+20-2 = 68, so only 3 units are involved.This is no coincidence; in many other cases paying with euros is more efficient than paying with guilders. On average the Euro is more efficient. This has nothing to do, of course, with the value of the Euro, but with the units chosen. The units for guilders used to be: 1, 2.5, 5, 10, 25, 50,whereas the units for the Euro are: 1, 2, 5, 10, 20, 50.
For this problem we restrict ourselves to amounts up to 100 cents. The Euro has coins with values 1, 2, 5, 10, 20, 50 eurocents. In paying an arbitrary amount in the range [1, 100] eurocents, on average 2.96 coins are involved, either as payment or as change. The Euro series is not optimal in this sense. With coins 1, 24, 34, 39, 46, 50 an amount of 68 cents can be paid using two coins.The average number of coins involved in paying an amount in the range [1, 100] is 2.52.
Calculations with the latter series are more complex, however. That is, mental calculations.These calculations could easily be programmed in any mobile phone, which nearly everybody carries around nowadays. Preparing for the future, a committee of the European Central Bank is studying the efficiency of series of coins, to find the most efficient series for amounts up to 100 eurocents. They need your help.
Write a program that, given a series of coins, calculates the average and maximum number of coins needed to pay any amount up to and including 100 cents. You may assume that both parties involved have sufficient numbers of any coin at their disposal.
Input
Output
Sample Input
3
1 2 5 10 20 50
1 24 34 39 46 50
1 2 3 7 19 72
Sample Output
2.96 5
2.52 3
2.80 4
Q : 如何处理找零
A : dp[v] = min{dp[v-w[i]]+1, dp[v+w[i]]+1}. 针对此题(尚不了解方法是否有普适性), 可以先求一步不找零情况下的完全背包问题, 然后再进行一步完全背包, 比较哪种方案用的个数较少
思路:
1. 令 dp[v] 表示拼出总面额为 v 的钱所需要的最少硬币数
2. 求解一步完全背包, 这一步假设不允许找零, dp[v] = min(dp[v], dp[v-w[i]]+1)
3. 然后由状态转移方程, 求解找零的最优解, dp[v] = min(dp[v], dp[v+w[i]+1)
总结:
1. 完全背包问题, 当 dp[i] = f(dp[i+xxx]) 时, 第二层循环是从大到小遍历, 因为完全背包要求等式右边是同行的数据(假如使用二维矩阵存储dp[i][j]的话)
2. 找零问题会使总的钱数超过目标值, 比如为了得到 goal(100), 可能给对方150, 对方找回 50, 因此 dp 数组需要开大一点
3. 第二步完全背包, 状态转移方程 dp[v] = min(dp[v], dp[v-w[i]+1), 为了方便理解还是先转化为二维空间存储最优解
dp[i][v] = min(dp[i-1][v], dp[i][v-w[i]]+1)
dp[i-1][v] 表示前 i-1 个硬币可以当做零钱找回的情况下的最优解, 当考虑到第 i 个硬币时, 假如把其当做了零钱, 那么若满足 dp[i][v+w[i]]+1 > dp[i-1][v], 则说明先把钱累积到 v+w[i], 然后再找一次零钱 w[i] 要比直接累积到 v 使用的硬币数少(说法不严谨, 但大致是这个意思)
逆着分析, 是有些难以理解
代码:
#include <iostream>
using namespace std;
const int MAXN = 110;
const int MAXM = 100*20;
const int n = 6;
int money[MAXN];
int dp[MAXM+10];
/*
* 不允许找钱, 前 i 个 coin 相加恰好为 x money
* 最大的money 总额可能会超过 100
* 完全背包, 每件物品可以放任意多次, 第二层循环(j) 从小到大遍历
*/
void withoutChange() {
memset(dp, 0x3f, sizeof(dp));
dp[0] = 0; // "恰好"
for(int i = 0; i < n; i++) {
for(int j = money[i]; j <= MAXM; j ++) {
dp[j] = min(dp[j], dp[j-money[i]]+1);
}
}
}
/*
* 允许找钱
* 对 i, 枚举找回的钱
* 允许找钱, 同时意味着一方给的钱可能会超过 100, 题目已经说明, 每组数据都包含1, 所以, 数据若是比较苛刻的话, maxn 得设置为 99 * 50
* 状态转移方程的方向变了, 同时完全背包要求等式右边是新的数据, 因此, j 的遍历顺序为从大到小
* dp[v] = min(dp[v], dp[v+w[i]]) 对于第 i 个硬币, 要么作为零钱, 要么不作为, 反过来, 好难想
*/
void withChange() {
for(int i = 0; i < n; i ++) {
for(int j = MAXM-money[i]; j >= 1; j --) {
dp[j] = min(dp[j], dp[j+money[i]]+1);
}
}
} int main() {
freopen("E:\\Copy\\ACM\\测试用例\\in.txt", "r", stdin);
int testCase;
cin >> testCase;
while(testCase--) {
for(int i = 0; i < n; i ++) {
scanf("%d", &money[i]);
}
float avg_coin = 0.0;
int max_coin = 0;
// first step
withoutChange();
// second step
withChange();
for(int i = 1; i <= 100; i ++) {
avg_coin += dp[i];
max_coin = max(max_coin, dp[i]);
}
avg_coin = avg_coin/100;
printf("%0.2f %d\n", avg_coin, max_coin);
}
return 0;
}
POJ 1252 Euro Efficiency(完全背包, 找零问题, 二次DP)的更多相关文章
- POJ 1252 Euro Efficiency ( 完全背包变形 && 物品重量为负 )
题意 : 给出 6 枚硬币的面值,然后要求求出对于 1~100 要用所给硬币凑出这 100 个面值且要求所用的硬币数都是最少的,问你最后使用硬币的平均个数以及对于单个面值所用硬币的最大数. 分析 : ...
- POJ 3260 The Fewest Coins(多重背包问题, 找零问题, 二次DP)
Q: 既是多重背包, 还是找零问题, 怎么处理? A: 题意理解有误, 店主支付的硬币没有限制, 不占额度, 所以此题不比 1252 难多少 Description Farmer John has g ...
- POJ 1252 Euro Efficiency(最短路 完全背包)
题意: 给定6个硬币的币值, 问组成1~100这些数最少要几个硬币, 比如给定1 2 5 10 20 50, 组成40 可以是 20 + 20, 也可以是 50 -10, 最少硬币是2个. 分析: 这 ...
- POJ 1252 Euro Efficiency
背包 要么 BFS 意大利是说给你几个基本的货币,组成 1~100 所有货币,使用基本上的货币量以最小的. 出口 用法概率.和最大使用量. 能够BFS 有可能 . 只是记得数组开大点. 可能会出现 1 ...
- Euro Efficiency(完全背包)
Euro Efficiency Time Limit : 2000/1000ms (Java/Other) Memory Limit : 20000/10000K (Java/Other) Tot ...
- [LeetCode] Coin Change 2 硬币找零之二
You are given coins of different denominations and a total amount of money. Write a function to comp ...
- [LeetCode] 518. Coin Change 2 硬币找零之二
You are given coins of different denominations and a total amount of money. Write a function to comp ...
- POJ Euro Efficiency 1252
Euro Efficiency Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 4109 Accepted: 1754 D ...
- HDU3591找零,背包
题目大概的意思就是:小强用硬币买东西,硬币有N种,面值为Vi,店家有各种硬币都有无限个,而小强只有Ci个(分别对应Vi) 问最小交易硬币数,就是一个有找零的背包问题啦. 我的上一篇博客跟这hdu359 ...
随机推荐
- LeetCode 新题: Find Minimum in Rotated Sorted Array 解题报告-二分法模板解法
Find Minimum in Rotated Sorted Array Question Solution Suppose a sorted array is rotated at some piv ...
- SharePoint自动化系列——通过PowerShell创建SharePoint Lists
转载请注明出自天外归云的博客园:http://www.cnblogs.com/LanTianYou/ 代码如下(保存到本地ps1文件中,右键run with PowerShell即可): Add-PS ...
- C#与C++区别
C#是三大主流OOP(面向对象编程)语言(C++,Java,C#)之一,也是最新的一种,其中必然借鉴了前两者的长处,“否则它的缔造者就该打屁股”——候捷语,见<C#Primer中文版>的译 ...
- 一款由jQuery实现的手风琴式相册图片展开效果
之前我们有分享过很多jQuery手风琴样式的菜单,比如CSS3手风琴下拉菜单.今天要分享的jQuery手风琴效果很特别,它是手风琴样式的相册图片展开效果.我们只需点击图片缩略图即可展开当前的图片,并将 ...
- 【工具】小巧好用的屏幕截图工具——ScrToPic
百度搜ScrToPic,有绿色版的用. 好处: 小巧快捷,不用为了截图而开QQ,不用看QQ的弹窗广告. 可以自定义截图区域和窗口捕捉,可以自定义这两个功能的快捷键. 截图时可以选择要不要显示鼠标. 窗 ...
- 【WPF】C#代码动态添加控件的Margin属性
需求:一组按钮的数据是从服务器中Json数据发过来的,需要根据这个Json数据动态地添加这组按钮. 工具:使用http://www.newtonsoft.com/json来解析Json. 过程:C#代 ...
- 【WPF/WAF】主界面(ShellWindow)引入别的界面布局
问题:主界面如果只用一个布局文件ShellWindow.xaml,会写得很大很臃肿.需要分为多个布局文件,然后由主界面引入.参考http://waf.codeplex.com/官方的BookLibra ...
- [uboot]在uboot里面添加环境变量使用run来执行
转自:http://blog.csdn.net/yangzheng_yz/article/details/41038259 在移植uboot的时候,可以在uboot里面添加定义一些自己的环境变量,这些 ...
- 基于at91sam9g10的工控板
1 eth0: 片选 NCS2 中断 PC7 复位 PC6 2 eth1: 片选 NCS3 中断 PC5 复位 PC4 3 扩展输入GPIO0-7: PB27 PB26 PB9 PB8 PB7 PB5 ...
- Android Animation动画效果简介
AlphaAnimation 淡入淡出动画 <alpha>A fade-in or fade-out animation. Represents an AlphaAnimation. a ...