Рассчитайте чаевые, используя наименьшее количество монет

23

Большинство приложений калькулятор чаевых просто взять фиксированный процент от цены еды. Так, например, если ваша еда стоит 23,45 долларов, вы можете оставить чаевые в размере 15% = 3,52 доллара или более щедрые чаевые в размере 20% = 4,69 доллара.

Достаточно удобно для пользователей кредитных карт. Но не так, если вы предпочитаете оставлять денежные чаевые, и в этом случае эти чудовищные суммы будут мешать. Итак, давайте изменим идею, чтобы она была более удобной для пользователей наличными.

Ваше назначение

Напишите, как можно меньше байт, программу или функцию, которая принимает в качестве входных данных:

  • Стоимость еды
  • Минимальный процент чаевых
  • Максимальный процент чаевых

И выведите любую сумму чаевых в диапазоне [цена * min_percentage / 100, цена * max_percentage / 100], которая минимизирует количество требуемых купюр / банкнот и монет.

Предположим, что денежные номиналы в США составляют 1, 5, 10, 25, 1, 5, 10, 20, 50 и 100 долларов.

пример

Вот пример не-игры в гольф на Python:

import math
import sys

# Do the math in cents so we can use integer arithmetic
DENOMINATIONS = [10000, 5000, 2000, 1000, 500, 100, 25, 10, 5, 1]

def count_bills_and_coins(amount_cents):
    # Use the Greedy method, which works on this set of denominations.
    result = 0
    for denomination in DENOMINATIONS:
        num_coins, amount_cents = divmod(amount_cents, denomination)
        result += num_coins
    return result

def optimize_tip(meal_price, min_tip_percent, max_tip_percent):
    min_tip_cents = int(math.ceil(meal_price * min_tip_percent))
    max_tip_cents = int(math.floor(meal_price * max_tip_percent))
    best_tip_cents = None
    best_coins = float('inf')
    for tip_cents in range(min_tip_cents, max_tip_cents + 1):
        num_coins = count_bills_and_coins(tip_cents)
        if num_coins < best_coins:
            best_tip_cents = tip_cents
            best_coins = num_coins
    return best_tip_cents / 100.0

# Get inputs from command-line
meal_price = float(sys.argv[1])
min_tip_percent = float(sys.argv[2])
max_tip_percent = float(sys.argv[3])
print('{:.2f}'.format(optimize_tip(meal_price, min_tip_percent, max_tip_percent)))

Некоторые примеры ввода и вывода:

~$ python tipcalc.py 23.45 15 20
4.00
~$ python tipcalc.py 23.45 15 17
3.55
~$ python tipcalc.py 59.99 15 25
10.00
~$ python tipcalc.py 8.00 13 20
1.05
dan04
источник
8
Если вы не используете кредитную карту, вы платите наличными, верно? Разве сумма чека + чаевых не будет соответствующей суммой, а не только чаевых?
Спарр
4
a program that takes as input (stdin, command-line arguments, or GUI input box, whichever is most convenient in your language)Это предназначено, чтобы переопределить наши значения по умолчанию для входов и выходов? То есть, например, будет ли разрешена функция, которая принимает три числа и возвращает результат?
Лайкони
3
Я правильно говорю , что 3.51и 3.75также действительные выходы для теста 23.45 15 17? Они используют одинаковое количество монет и также находятся внутри диапазона.
Кевин Круйссен
3
@Sparr Даже люди, которые оплачивают счет картой, любят оставлять чаевые; для этого есть разные причины, поэтому я не буду их здесь повторять.
Нил
3
@Laikoni: я отредактировал требования для использования «программы или функции» по умолчанию для сайта и поэтому задним числом принимаю существующие ответы только для функций.
апреля

Ответы:

3

Древесный уголь , 60 байт

Nθ≔×θNη≔×θNζ≔⁰θFI⪪”;‴üφ↷Σ↗SEX&¿h'⊟”³«W‹θη≧⁺ιθ¿›θζ≧⁻ιθ»﹪%.2fθ

Попробуйте онлайн!Принимает ввод в виде десятичных дробей. Ссылка на подробную версию кода. Объяснение:

Nθ

Введите счет.

≔×θNη≔×θNζ

Введите десятичные дроби наконечника и вычислите минимальный и максимальный наконечник.

≔⁰θ

Начните с нулевого наконечника.

FI⪪”;‴üφ↷Σ↗SEX&¿h'⊟”³«

Строка SEXy раскрывается, в 10050.20.10.5.01.0.250.1.05.01которой разбивается на группы из трех символов и приводится к плавающей точке .

W‹θη≧⁺ιθ

Добавьте столько номиналов, сколько необходимо для достижения минимального чаевого.

¿›θζ≧⁻ιθ»

Удалите один номинал, если максимальный наконечник был превышен.

﹪%.2fθ

Отформатируйте подсказку для отображения.

Нил
источник
1
Я не думаю, что форматирование было требованием (скорее всего то, что делает пример кода).
Джонатан Аллан
@JonathanAllan В этом случае вы можете сэкономить 4 байта, используя вместо ﹪%.2f.
Нил
6

JavaScript (ES6), 93 байта

(x,m,M)=>(g=(t,c=1e4)=>t>x*M?0:t<x*m?[...'1343397439'].some(d=>g(t+(c/=-~d/2)))*r:r=t)(0)/100

Попробуйте онлайн!

Как?

Мы рекурсивно вычисляем сумму значений купюры / монеты до тех пор, пока она не попадет в допустимый диапазон, всегда сначала пробуя самое высокое значение.

{b0,,bn}

  • все слагаемые от до b n являются обязательными, иначе алгоритм выбрал бы { b 0 , ,b0bn{b0,,bk1,x}xbk0k<n
  • для любого и любого x b n , { b 0 , , b k - 1 , b k - x , b k + 10k<nxbn{b0,,bk1,bkx,bk+1,,bn}{b0,,bn1}
  • может существовать некоторое 0<x<bn{b0,,bn1,x}

cn

{c0=10000cn+1=cn(dn+1)/2

(d0,,d9)=(1,3,4,3,3,9,7,4,3,9)

 n | c(n)  | d(n) | k = (d(n)+1)/2 | c(n+1) = c(n)/k
---+-------+------+----------------+-----------------
 0 | 10000 |   1  | (1+1)/2 = 1    |      10000
 1 | 10000 |   3  | (3+1)/2 = 2    |       5000
 2 |  5000 |   4  | (4+1)/2 = 2.5  |       2000
 3 |  2000 |   3  | (3+1)/2 = 2    |       1000
 4 |  1000 |   3  | (3+1)/2 = 2    |        500
 5 |   500 |   9  | (9+1)/2 = 5    |        100
 6 |   100 |   7  | (7+1)/2 = 4    |         25
 7 |    25 |   4  | (4+1)/2 = 2.5  |         10
 8 |    10 |   3  | (3+1)/2 = 2    |          5
 9 |     5 |   9  | (9+1)/2 = 5    |          1
Arnauld
источник
4

Python 3.x: 266 185 байт

Простая модификация моего примера программы в вопросе. Обратите внимание, что вывод больше не отформатирован и требует 2 десятичных знака.

Редактировать: Спасибо Джо Кинг за уменьшение.

import sys
p,m,M,T=*map(float,sys.argv[1:]),0
C=p*M
for t in range(-int(-p*m),int(p*M)+1):
 n,a=0,t
 for d in 1e4,5e3,2e3,1e3,500,100,25,10,5,1:n+=a//d;a%=d
 if n<C:T,C=t,n
print(T/100)
dan04
источник
1
Немного быстрой игры в гольф, чтобы получить его до 185 байтов
Джо Кинг,
4

Java 10, 186 185 байт

(p,m,M)->{double r=0,t,Q=99,q;for(m*=p+.02;m<M*p;m+=.01){q=0;t=m;for(var c:new double[]{100,50,20,10,5,1,.25,.1,.05,.01})for(;t>=c;t-=c)q++;if(q<Q){Q=q;r=m;}}return"".format("%.2f",r);}

Принимает минимальный и максимальный проценты в виде /100десятичных дробей (то есть 15%как 0.15).

-1 байт, чтобы исправить проблему с 3.51потенциальным выходным сигналом, а также способ исправить ошибки округления на 1 байт одновременно.

Попробуйте онлайн.

Объяснение:

(p,m,M)->{                // Method with three double parameters and String return-type
  double r=0,             //  Result-double, starting at 0
         t,               //  Temp-double
         Q=99,            //  Min amount of coins, starting at 99
         q;               //  Temp-double for the amount of coins
  for(m*=p-.02;m<M*p;     //  Loop in the range [`m*p-0.02`, `M*p`]
           m+=.01){       //  in steps of 0.01 (1 cent) per iteration
                          //  (the -0.02 (minus 2 cents) is to fix rounding errors)
    q=0;                  //   Reset `q` to 0
    t=m;                  //   Reset `t` to the current iteration `m`
    for(var c:new double[]{100,50,20,10,5,1,.25,.1,.05,.01})
                          //   Loop over the coins (largest to smallest)
      for(;t>=c;          //    As long as `t` is larger than or equal to the current coin
          t-=c)           //     Remove the coin from the value `t`
          q++;            //     And increase the quantity-counter by 1
      if(q<Q){            //   If the quantity-counter is smaller than the current smallest
        Q=q;              //    Replace the smallest with the current
        r=m;}}            //    And replace the result with the current `m`
  return"".format("%.2f",r)l;}
                          //  Return the result with 2 decimal places
Кевин Круйссен
источник
Я не думаю, что это технически актуально на данный момент, так как в вопросе указана программа, но ОП не уточнил.
Οurous
1
OP теперь имеет разрешенные функции, поэтому вам не нужно беспокоиться об удвоении размера.
Οurous
3

Чисто , 207 156 байт

Замена на функцию сэкономила 51 байт, что неудивительно.

import StdEnv
d=[10000,2000,1000,500,100,25,10,5,1]
$n u l=snd(hd(sort[(sum[foldl(rem)m(d%(0,i))/k\\k<-d&i<-[-1..]],toReal m)\\m<-map toInt[n*u..n*l]]))/1E2

Попробуйте онлайн!

Οurous
источник
2
ОП уточнил, что функции теперь разрешены.
Лайкони
@Laikoni Спасибо, что сообщили мне :) Сохраняет много байтов - полные программы стоят дорого в Clean!
Οurous
2

Питон ( 264 222 байта)

Чуть больше в гольф.

m=[.01,.05,.1,.25,.5,1,5,10,20,50,100]
def f(a,i,j):
 t,u=9**9,a*j
 def g(s,d,c):
  nonlocal t
  if(a*i<s<u)+(c>t):t=min(c,t);return c,s
  return(t+1,s)if(s>u)+(d>9)else min(g(s+m[d],d,c+1),g(s,d+1,c))
 return g(0,0,0)[1]

Попробуйте онлайн!

Захари Хлопок
источник
2

Perl 6 , 93 92 89 байт

{.01*($^a*$^b+|0...$a*$^c).min:{$!=$_;sum '✐ᎈߐϨǴd
'.ords>>.&{($!%=$_)xx$!/$_}}}

Попробуйте онлайн!

Блок анонимного кода, который принимает три аргумента (цена, минимальный процент и максимальный процент) и возвращает подсказку.

Джо Кинг
источник
0

Желе ,  33  32 байта

“ñṇzi;’b⁴×H¥\ɓ_>Ƈ-Ṫ
PĊ1¦r/ÇƬL$ÞḢ

Монадическая ссылка, принимающая список, [cost in cents, [minimum ratio, maximum ratio]]который дает сумму чаевых в центах.

Попробуйте онлайн!

Как?

Первая строка - это вспомогательная ссылка, которая выдает сумму, указанную за вычетом купюры / монеты самого большого номинала:

“ñṇzi;’b⁴×H¥\ɓ_>Ƈ-Ṫ - Link 1, get next lower amount: integer, V
“ñṇzi;’             - base 250 number = 112835839060
       b⁴           - to base 16 = [1,10,4,5,8,10,4,4,5,4]
            \       - cumulative reduce with:       e.g.: 1,10   5,4   10,5   25,8
           ¥        -   last two links as a dyad:
         ×          -     multiply                        10     20    50     200
          H         -     halve                            5     10    25     100
                    - ...yielding: [1,5,10,25,100,500,1000,2000,5000,10000]
             ɓ      - start a new dyadic link with swapped arguments
              _     - subtract (vectorises) ...i.e. [V-1,V-5,V-10,...]
                Ƈ   - filter keep those which satisfy:
                 -  -   literal -1
               >    -   greater than? (i.e. if V-X > -1)
                  Ṫ - tail (tailing an empty list yields 0)

Количество вызовов, необходимое для достижения нуля, используется для сортировки диапазона сумм чаевых, а затем получается крайний левый:

PĊ1¦r/ÇƬL$ÞḢ - Main Link: [cost, [min, max]]
P            - product = [cost*min, cost*max]
   ¦         - sparse application...
  1          - ...to indices: 1
 Ċ           - ...what: ceiling   -> [ceil(cost*min), cost*max]
     /       - reduce by:
    r        -   inclusive range (implicit floor of arguments)
          Þ  - sort by:
         $   -   last two links as a monad:
       Ƭ     -     repeat collecting results until a fixed point is reached:
      Ç      -       last link (1) as a monad  (e.g. 32 -> [32,7,2,1,0])
        L    -     length (i.e. coins/notes required + 1)
           Ḣ - head
Джонатан Аллан
источник