Berechnen Sie einen Tipp mit der kleinsten Anzahl von Münzen

23

Die meisten Trinkgeldrechner-Apps nehmen einfach einen pauschalen Prozentsatz des Essenspreises ein. Wenn Ihre Mahlzeit beispielsweise 23,45 USD beträgt, können Sie ein Trinkgeld von 15% = 3,52 USD oder ein großzügigeres Trinkgeld von 20% = 4,69 USD hinterlassen.

Praktisch genug für Kreditkartenbenutzer. Aber nicht, wenn Sie lieber Bargeld-Trinkgelder abgeben möchten. In diesem Fall behindern Sie diese seltsamen Cent-Beträge. Ändern wir also die Idee, um sie für Bargeldbenutzer angenehmer zu gestalten.

Ihre Aufgabe

Schreiben Sie in so wenigen Bytes wie möglich ein Programm oder eine Funktion , die als Eingabe verwendet wird:

  • Preis der Mahlzeit
  • Minimaler Trinkgeldanteil
  • Maximaler Trinkgeldanteil

Und geben Sie einen beliebigen Trinkgeldbetrag im Bereich [Preis * Mindestprozentsatz / 100, Preis * Höchstprozentsatz / 100] aus, der die Anzahl der erforderlichen Scheine / Banknoten und Münzen minimiert.

Angenommen, die US-Währungsbezeichnungen lauten 1, 5, 10, 25, 1, 5, 10, 20, 50 und 100 US-Dollar.

Beispiel

Hier ist ein nicht-golfendes Beispielprogramm 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)))

Einige Beispieleingaben und -ausgaben:

~$ 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
quelle
8
Wenn Sie keine Kreditkarte verwenden, bezahlen Sie in bar, oder? Wäre dann nicht die Summe von check + tip der relevante Betrag, nicht nur das Trinkgeld?
Sparr
4
a program that takes as input (stdin, command-line arguments, or GUI input box, whichever is most convenient in your language)Soll dies unsere Standardeinstellungen für Ein- und Ausgänge überschreiben? Das heißt, wäre z. B. eine Funktion zulässig, die drei Zahlen akzeptiert und das Ergebnis zurückgibt?
Laikoni
3
Stimmt das 3.51und 3.75sind das auch gültige Ausgaben für den Testfall 23.45 15 17? Sie verbrauchen die gleiche Menge an Münzen und befinden sich ebenfalls innerhalb der Reichweite.
Kevin Cruijssen
3
@Sparr Auch Leute, die die Rechnung mit der Karte bezahlen, hinterlassen gerne ein Bargeld-Trinkgeld. Dafür gibt es verschiedene Gründe, deshalb werde ich sie hier nicht wiederholen.
Neil
3
@Laikoni: Ich habe die Anforderungen für die Verwendung des Site-Standards "Programm oder Funktion" bearbeitet und akzeptiere daher rückwirkend die vorhandenen Nur-Funktions-Antworten.
Dan04

Antworten:

3

Kohle , 60 Bytes

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

Probieren Sie es online! Nimmt Eingaben als Dezimalstellen. Link ist eine ausführliche Version des Codes. Erläuterung:

Nθ

Geben Sie die Rechnung ein.

≔×θNη≔×θNζ

Geben Sie die Spitzen-Dezimalbrüche ein und berechnen Sie die minimale und maximale Spitze.

≔⁰θ

Beginnen Sie mit der Nullspitze.

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

Die SEXy-Zeichenfolge wird erweitert und 10050.20.10.5.01.0.250.1.05.01in Gruppen mit drei Zeichen aufgeteilt und in Floating umgewandelt.

W‹θη≧⁺ιθ

Fügen Sie so viele Stückelungen wie nötig hinzu, um die minimale Spitze zu erreichen.

¿›θζ≧⁻ιθ»

Entfernen Sie eine Stückelung, wenn die maximale Spitze überschritten wurde.

﹪%.2fθ

Formatieren Sie den Tipp für die Anzeige.

Neil
quelle
1
Ich denke nicht, dass die Formatierung eine Anforderung war (eher etwas, das der Beispielcode tut).
Jonathan Allan
@ JonathanAllan Nun, in diesem Fall könnten Sie 4 Bytes sparen, indem Sie anstelle von ﹪%.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

Probieren Sie es online!

Wie?

Wir berechnen rekursiv eine Summe von Banknoten- / Münzenwerten, bis sie in den akzeptablen Bereich fällt, wobei immer der höchste Wert zuerst versucht wird.

{b0,,bn}

  • b0bn{b0,,bk-1,x}xbk0k<n
  • 0k<nxbn{b0,,bk-1,bk-x,bk+1,,bn}{b0,,bn-1}
  • 0<x<bn{b0,,bn-1,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
quelle
4

Python 3.x: 266 185 Bytes

Eine unkomplizierte Änderung meines Beispielprogramms in der Frage. Beachten Sie, dass die Ausgabe nicht mehr so ​​formatiert ist, dass 2 Dezimalstellen erforderlich sind.

Edit: Danke an Jo King für die Verkleinerung.

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
quelle
1
Schnelles Golfen, um 185 Bytes zu erreichen
Jo King
4

Java 10, 186 185 Bytes

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

Nimmt die minimalen und maximalen Prozentsätze als /100Dezimalstellen (dh 15%als 0.15).

-1 Byte, um das Problem mit 3.51der möglichen Ausgabe zu beheben und gleichzeitig Rundungsfehler um 1 Byte zu beheben.

Probieren Sie es online aus.

Erläuterung:

(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
Kevin Cruijssen
quelle
Ich denke nicht, dass dies im Moment technisch gültig ist, da die Frage ein Programm spezifiziert, aber das OP nicht geklärt hat.
Urous
1
OP hat klargestellt, dass jetzt Funktionen zulässig sind, sodass Sie sich nicht um die Verdoppelung der Größe kümmern müssen.
Urous
3

Sauber , 207 156 Bytes

Das Wechseln zu einer Funktion sparte, nicht überraschend, 51 Byte.

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

Probieren Sie es online!

Οurous
quelle
2
OP hat klargestellt, dass jetzt Funktionen erlaubt sind.
Laikoni
@Laikoni Danke, dass du mich informiert hast :) Spart eine Menge Bytes - volle Programme sind in Clean teuer!
Οurous
2

Python ( 264 222 Bytes)

Etwas mehr Golf.

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]

Probieren Sie es online!

Zachary Cotton
quelle
2

Perl 6 , 93 92 89 Bytes

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

Probieren Sie es online!

Anonymer Codeblock, der drei Argumente (Preis, Mindestprozentsatz und Höchstprozentsatz) akzeptiert und den Tipp zurückgibt.

Scherzen
quelle
0

Kotlin , 215 Bytes

{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}

Probieren Sie es online!

JohnWells
quelle
0

Jelly ,  33  32 Bytes

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

Ein monadischer Link, der eine Liste akzeptiert, [cost in cents, [minimum ratio, maximum ratio]]die einen Trinkgeldbetrag in Cent ergibt.

Probieren Sie es online!

Wie?

Die erste Zeile ist ein Hilfslink, der den angegebenen Betrag abzüglich der größten Nennwertnote / Münze ergibt:

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

Die Anzahl der Anrufe, die erforderlich sind, um Null zu erreichen, wird verwendet, um den Bereich der Trinkgeldbeträge zu sortieren, und dann wird ganz links ausgegeben:

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
Jonathan Allan
quelle