Calcola un suggerimento usando il minor numero di monete


23

La maggior parte delle app per calcolatori di mance prende semplicemente una percentuale fissa del prezzo del pasto. Ad esempio, se il tuo pasto è di $ 23,45, puoi lasciare una mancia del 15% = $ 3,52 o una mancia più generosa del 20% = $ 4,69.

Abbastanza conveniente per gli utenti di carte di credito. Ma non è così se preferisci lasciare delle mance in contanti, nel qual caso questi importi stranissimi si frappongono. Quindi modifichiamo l'idea per essere più conveniente per gli utenti di denaro contante.

Il tuo incarico

Scrivi, nel minor numero di byte possibile, un programma o una funzione che accetta come input:

  • Prezzo del pasto
  • Percentuale minima di mancia
  • Percentuale massima di punta

E genera qualsiasi importo di mancia all'interno dell'intervallo [prezzo * percentuale_min / 100, prezzo * percentuale_ max / 100] che minimizza il numero di banconote / banconote e monete richieste.

Assumi le denominazioni monetarie statunitensi di 1 ¢, 5 ¢, 10 ¢, 25 ¢, $ 1, $ 5, $ 10, $ 20, $ 50 e $ 100.

Esempio

Ecco un programma di esempio senza golf in 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)))

Alcuni input e output di esempio:

~$ 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

8
Se non stai utilizzando una carta di credito, stai pagando in contanti, giusto? Il totale dell'assegno + mancia non sarebbe quindi l'importo rilevante, non solo la mancia?
Sparr,

4
a program that takes as input (stdin, command-line arguments, or GUI input box, whichever is most convenient in your language)Questo ha lo scopo di sostituire i nostri valori predefiniti per ingressi e uscite? Cioè, ad esempio una funzione che accetta tre numeri e restituisce il risultato sarebbe consentita?
Laikoni,

3
Ho ragione a dirlo 3.51e 3.75sono anche uscite valide per il test case 23.45 15 17? Usano la stessa quantità di monete e sono anche all'interno dell'intervallo.
Kevin Cruijssen, il

3
@Sparr Anche le persone che pagano il conto con la carta amano lasciare una mancia; ci sono varie ragioni per questo, quindi non le ripeterò qui.
Neil,

3
@Laikoni: ho modificato i requisiti per utilizzare il "programma o funzione" predefinito dal sito, quindi accetto retroattivamente le risposte di sola funzione esistenti.
dan04,

Risposte:


3

Carbone , 60 byte

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

Provalo online! Accetta input come decimali. Il collegamento è alla versione dettagliata del codice. Spiegazione:

Nθ

Inserisci il conto.

≔×θNη≔×θNζ

Immettere le frazioni decimali della punta e calcolare il minimo e il massimo della punta.

≔⁰θ

Inizia con la punta zero.

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

La stringa SEXy si espande a 10050.20.10.5.01.0.250.1.05.01cui viene suddivisa in gruppi di tre caratteri e viene lanciata in virgola mobile.

W‹θη≧⁺ιθ

Aggiungi tutte le denominazioni correnti necessarie per raggiungere il suggerimento minimo.

¿›θζ≧⁻ιθ»

Rimuovere una denominazione se la punta massima è stata superata.

﹪%.2fθ

Formatta il suggerimento per la visualizzazione.


1
Non penso che la formattazione fosse un requisito (piuttosto solo qualcosa che fa il codice di esempio).
Jonathan Allan,

@JonathanAllan Bene, in tal caso puoi salvare 4 byte usando invece di ﹪%.2f.
Neil,

6

JavaScript (ES6), 93 byte

(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

Provalo online!

Come?

Calcoliamo in modo ricorsivo una somma di valori di banconote / monete finché non rientra nell'intervallo accettabile, provando sempre prima il valore più alto.

{b0,,bn}

  • b0bn{b0,,bk1,x}xbk0k<n
  • 0k<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

4

Python 3.x: 266 185 byte

Una semplice modifica al mio programma di esempio nella domanda. Si noti che l'output non è più formattato per richiedere 2 posizioni decimali.

Modifica: grazie a Jo King per averlo ridotto.

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)

1
Qualche veloce golf per arrivare a 185 byte
Jo King,

4

Java 10, 186 185 byte

(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);}

Prende le percentuali minima e massima come /100decimali (ovvero 15%come 0.15).

-1 byte per risolvere il problema con 3.51come potenziale output e golf il modo per correggere gli errori di arrotondamento di 1 byte contemporaneamente.

Provalo online.

Spiegazione:

(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

Non penso che questo sia tecnicamente valido al momento poiché la domanda specifica un programma, ma il PO non ha chiarito.
Οuroso

1
OP ha chiarito che ora le funzioni sono consentite, quindi non devi preoccuparti di raddoppiare le dimensioni.
Οuroso

3

Pulito , 207 156 byte

Lo scambio con una funzione ha consentito di risparmiare 51 byte, non sorprende.

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

Provalo online!


2
OP ha chiarito che le funzioni sono ora consentite.
Laikoni,

@Laikoni Grazie per avermelo detto :) Risparmia molti byte - i programmi completi sono costosi in Clean!
Οuroso

2

Python ( 264 222 byte)

Leggermente più golfato.

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]

Provalo online!


2

Perl 6 , 93 92 89 byte

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

Provalo online!

Blocco di codice anonimo che accetta tre argomenti (prezzo, percentuale minima e percentuale massima) e restituisce il suggerimento.



0

Kotlin , 215 byte

{p:Double,l:Int,h:Int->val d=listOf(10000,5000,2000,1000,500,100,25,10,5,1)
var m=Int.MAX_VALUE
var r=0.0
(Math.ceil(p*l).toInt()..(p*h).toInt()).map{var a=it
var c=0
d.map{c+=a/it
a%=it}
if(c<m){m=c
r=it/100.0}}
r}

Provalo online!


0

Gelatina ,  33  32 byte

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

Un collegamento monadico che accetta un elenco [cost in cents, [minimum ratio, maximum ratio]]che fornisce una mancia in centesimi.

Provalo online!

Come?

La prima riga è un collegamento helper che restituisce l'importo dato meno la banconota / moneta di denominazione maggiore:

“ñṇ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)

Il numero di chiamate necessarie per raggiungere lo zero viene utilizzato per ordinare l'intervallo di importi della mancia, quindi viene generato l'estrema sinistra:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.