|
| 1 | +package followup; |
| 2 | + |
| 3 | +public class Code01_Cola { |
| 4 | + /* |
| 5 | + * 买饮料 时间限制: 3000MS 内存限制: 589824KB 题目描述: |
| 6 | + * 游游今年就要毕业了,和同学们在携程上定制了日本毕业旅行。愉快的一天行程结束后大家回到了酒店房间,这时候同学们都很口渴, |
| 7 | + * 石头剪刀布选出游游去楼下的自动贩卖机给大家买可乐。 贩卖机只支持硬币支付,且收退都只支持10 ,50,100 |
| 8 | + * 三种面额。一次购买行为只能出一瓶可乐,且每次购买后总是找零最小枚数的硬币。(例如投入100圆,可乐30圆,则找零50圆一枚,10圆两枚) |
| 9 | + * 游游需要购买的可乐数量是 m,其中手头拥有的 10,50,100 面额硬币的枚数分别是 a,b,c,可乐的价格是x(x是10的倍数)。 |
| 10 | + * 如果游游优先使用大面额购买且钱是够的情况下,请计算出需要投入硬币次数? 输入描述 依次输入, 需要可乐的数量为 m 10元的张数为 a 50元的张数为 b |
| 11 | + * 100元的张树为 c 1瓶可乐的价格为 x 输出描述 输出当前金额下需要投入硬币的次数 |
| 12 | + * 例如需要购买2瓶可乐,每瓶可乐250圆,手里有100圆3枚,50圆4枚,10圆1枚。 购买第1瓶投递100圆3枚,找50圆 购买第2瓶投递50圆5枚 |
| 13 | + * 所以是总共需要操作8次金额投递操作 样例输入 2 1 4 3 250 样例输出 8 |
| 14 | + */ |
| 15 | + |
| 16 | + // 暴力尝试,为了验证正式方法而已 |
| 17 | + public static int right(int m, int a, int b, int c, int x) { |
| 18 | + int[] qian = { 100, 50, 10 }; |
| 19 | + int[] zhang = { c, b, a }; |
| 20 | + int puts = 0; |
| 21 | + while (m != 0) { |
| 22 | + int cur = buy(qian, zhang, x); |
| 23 | + if (cur == -1) { |
| 24 | + return -1; |
| 25 | + } |
| 26 | + puts += cur; |
| 27 | + m--; |
| 28 | + } |
| 29 | + return puts; |
| 30 | + } |
| 31 | + |
| 32 | + public static int buy(int[] qian, int[] zhang, int rest) { |
| 33 | + int first = -1; |
| 34 | + for (int i = 0; i < 3; i++) { |
| 35 | + if (zhang[i] != 0) { |
| 36 | + first = i; |
| 37 | + break; |
| 38 | + } |
| 39 | + } |
| 40 | + if (first == -1) { |
| 41 | + return -1; |
| 42 | + } |
| 43 | + if (qian[first] >= rest) { |
| 44 | + zhang[first]--; |
| 45 | + giveRest(qian, zhang, first + 1, qian[first] - rest, 1); |
| 46 | + return 1; |
| 47 | + } else { |
| 48 | + zhang[first]--; |
| 49 | + int next = buy(qian, zhang, rest - qian[first]); |
| 50 | + if (next == -1) { |
| 51 | + return -1; |
| 52 | + } |
| 53 | + return 1 + next; |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + // 正式的方法 |
| 58 | + public static int putTimes(int m, int a, int b, int c, int x) { |
| 59 | + // 0 1 2 |
| 60 | + int[] qian = { 100, 50, 10 }; |
| 61 | + int[] zhang = { c, b, a }; |
| 62 | + // 总共需要多少次投币 |
| 63 | + int puts = 0; |
| 64 | + // 之前面值的钱还剩下多少总钱数 |
| 65 | + int preQianRest = 0; |
| 66 | + // 之前面值的钱还剩下多少总张数 |
| 67 | + int preQianZhang = 0; |
| 68 | + for (int i = 0; i < 3 && m != 0; i++) { |
| 69 | + // 要用之前剩下的钱、当前面值的钱,共同买第一瓶可乐 |
| 70 | + // 之前的面值剩下多少钱,是preQianRest |
| 71 | + // 之前的面值剩下多少张,是preQianZhang |
| 72 | + // 之所以之前的面值会剩下来,一定是剩下的钱,一直攒不出一瓶可乐的单价 |
| 73 | + // 当前的面值付出一些钱+之前剩下的钱,此时有可能凑出一瓶可乐来 |
| 74 | + // 那么当前面值参与搞定第一瓶可乐,需要掏出多少张呢?就是curQianFirstBuyZhang |
| 75 | + int curQianFirstBuyZhang = (x - preQianRest + qian[i] - 1) / qian[i]; |
| 76 | + if (zhang[i] >= curQianFirstBuyZhang) { // 如果之前的钱和当前面值的钱,能凑出第一瓶可乐 |
| 77 | + // 凑出来了一瓶可乐也可能存在找钱的情况, |
| 78 | + giveRest(qian, zhang, i + 1, (preQianRest + qian[i] * curQianFirstBuyZhang) - x, 1); |
| 79 | + puts += curQianFirstBuyZhang + preQianZhang; |
| 80 | + zhang[i] -= curQianFirstBuyZhang; |
| 81 | + m--; |
| 82 | + } else { // 如果之前的钱和当前面值的钱,不能凑出第一瓶可乐 |
| 83 | + preQianRest += qian[i] * zhang[i]; |
| 84 | + preQianZhang += zhang[i]; |
| 85 | + continue; |
| 86 | + } |
| 87 | + // 凑出第一瓶可乐之后,当前的面值有可能能继续买更多的可乐 |
| 88 | + // 以下过程就是后续的可乐怎么用当前面值的钱来买 |
| 89 | + // 用当前面值的钱,买一瓶可乐需要几张 |
| 90 | + int curQianBuyOneColaZhang = (x + qian[i] - 1) / qian[i]; |
| 91 | + // 用当前面值的钱,一共可以搞定几瓶可乐 |
| 92 | + int curQianBuyColas = Math.min(zhang[i] / curQianBuyOneColaZhang, m); |
| 93 | + // 用当前面值的钱,每搞定一瓶可乐,收货机会吐出多少零钱 |
| 94 | + int oneTimeRest = qian[i] * curQianBuyOneColaZhang - x; |
| 95 | + // 每次买一瓶可乐,吐出的找零总钱数是oneTimeRest |
| 96 | + // 一共买的可乐数是curQianBuyColas,所以把零钱去提升后面几种面值的硬币数, |
| 97 | + // 就是giveRest的含义 |
| 98 | + giveRest(qian, zhang, i + 1, oneTimeRest, curQianBuyColas); |
| 99 | + // 当前面值去搞定可乐这件事,一共投了几次币 |
| 100 | + puts += curQianBuyOneColaZhang * curQianBuyColas; |
| 101 | + // 还剩下多少瓶可乐需要去搞定,继续用后面的面值搞定去吧 |
| 102 | + m -= curQianBuyColas; |
| 103 | + // 当前面值可能剩下若干张,要参与到后续买可乐的过程中去, |
| 104 | + // 所以要更新preQianRest和preQianZhang |
| 105 | + zhang[i] -= curQianBuyOneColaZhang * curQianBuyColas; |
| 106 | + preQianRest = qian[i] * zhang[i]; |
| 107 | + preQianZhang = zhang[i]; |
| 108 | + } |
| 109 | + return m == 0 ? puts : -1; |
| 110 | + } |
| 111 | + |
| 112 | + public static void giveRest(int[] qian, int[] zhang, int i, int oneTimeRest, int times) { |
| 113 | + for (; i < 3; i++) { |
| 114 | + zhang[i] += (oneTimeRest / qian[i]) * times; |
| 115 | + oneTimeRest %= qian[i]; |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | + public static void main(String[] args) { |
| 120 | + int testTime = 1000; |
| 121 | + int zhangMax = 10; |
| 122 | + int colaMax = 10; |
| 123 | + int priceMax = 20; |
| 124 | + System.out.println("如果错误会打印错误数据,否则就是正确"); |
| 125 | + System.out.println("test begin"); |
| 126 | + for (int i = 0; i < testTime; i++) { |
| 127 | + int m = (int) (Math.random() * colaMax); |
| 128 | + int a = (int) (Math.random() * zhangMax); |
| 129 | + int b = (int) (Math.random() * zhangMax); |
| 130 | + int c = (int) (Math.random() * zhangMax); |
| 131 | + int x = ((int) (Math.random() * priceMax) + 1) * 10; |
| 132 | + int ans1 = putTimes(m, a, b, c, x); |
| 133 | + int ans2 = right(m, a, b, c, x); |
| 134 | + if (ans1 != ans2) { |
| 135 | + System.out.println("int m = " + m + ";"); |
| 136 | + System.out.println("int a = " + a + ";"); |
| 137 | + System.out.println("int b = " + b + ";"); |
| 138 | + System.out.println("int c = " + c + ";"); |
| 139 | + System.out.println("int x = " + x + ";"); |
| 140 | + break; |
| 141 | + } |
| 142 | + } |
| 143 | + System.out.println("test end"); |
| 144 | + } |
| 145 | + |
| 146 | +} |
0 commit comments