Hitung tip menggunakan jumlah koin terkecil

23

Sebagian besar aplikasi kalkulator tip hanya mengambil persentase datar dari harga makanan. Jadi, misalnya, jika makanan Anda adalah $ 23,45, Anda dapat memberikan tip 15% = $ 3,52, atau tip 20% yang lebih murah hati = $ 4,69.

Cukup nyaman untuk pengguna kartu kredit. Tetapi tidak demikian halnya jika Anda lebih suka meninggalkan tips uang tunai, dalam hal ini jumlah aneh ini menghalangi. Jadi, mari modifikasi ide agar lebih nyaman bagi pengguna uang tunai.

Tugas Anda

Tulis, sesedikit mungkin byte, program atau fungsi yang mengambil input:

  • Harga makanan
  • Persentase tip minimum
  • Persentase tip maksimum

Dan hasilkan jumlah tip dalam kisaran [harga * min_percentage / 100, harga * max_percentage / 100] yang meminimalkan jumlah tagihan / uang kertas dan koin yang diperlukan.

Asumsikan denominasi moneter AS sebesar 1 ¢, 5 ¢, 10 ¢, 25 ¢, $ 1, $ 5, $ 10, $ 20, $ 50, dan $ 100.

Contoh

Berikut adalah contoh program non-golf dengan 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)))

Beberapa input dan output sampel:

~$ 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
sumber
8
Jika Anda tidak menggunakan kartu kredit maka Anda membayar tunai, bukan? Bukankah total check + tip menjadi jumlah yang relevan, bukan hanya tip?
Sparr
4
a program that takes as input (stdin, command-line arguments, or GUI input box, whichever is most convenient in your language)Apakah ini dimaksudkan untuk mengesampingkan default kami untuk input dan output? Yaitu, apakah mis. Suatu fungsi yang mengambil tiga angka dan mengembalikan hasilnya diizinkan?
Laikoni
3
Apakah saya benar mengatakan itu 3.51dan 3.75juga keluaran yang valid untuk kasus uji 23.45 15 17? Mereka menggunakan jumlah koin yang sama dan juga berada di dalam jangkauan.
Kevin Cruijssen
3
@Sparr Bahkan orang yang membayar tagihan dengan kartu suka meninggalkan tip uang tunai; ada berbagai alasan yang diberikan untuk ini jadi saya tidak akan mengulanginya di sini.
Neil
3
@Laikoni: Saya telah mengedit persyaratan untuk menggunakan "program atau fungsi" default-situs, dan dengan demikian secara retroaktif menerima jawaban hanya fungsi yang ada.
dan04

Jawaban:

3

Arang , 60 byte

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

Cobalah online! Mengambil input sebagai desimal. Tautan adalah untuk mengucapkan versi kode. Penjelasan:

Nθ

Masukkan tagihan.

≔×θNη≔×θNζ

Masukkan fraksi desimal tip dan hitung minium dan tip maksimum.

≔⁰θ

Mulailah dengan nol tip.

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

String SEXy mengembang 10050.20.10.5.01.0.250.1.05.01yang dipecah menjadi kelompok-kelompok tiga karakter dan dilemparkan ke float.

W‹θη≧⁺ιθ

Tambahkan sebanyak mungkin denominasi saat ini untuk mencapai ujung minimum.

¿›θζ≧⁻ιθ»

Hapus satu denominasi jika ujung maksimal telah terlampaui.

﹪%.2fθ

Format ujung untuk tampilan.

Neil
sumber
1
Saya tidak berpikir format adalah persyaratan (bukan hanya sesuatu contoh kode tidak).
Jonathan Allan
@ Jonathan Allan Nah dalam hal ini Anda bisa menghemat 4 byte dengan menggunakan bukan ﹪%.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

Cobalah online!

Bagaimana?

Kami secara rekursif menghitung jumlah nilai tagihan / koin hingga masuk dalam kisaran yang dapat diterima, selalu mencoba nilai tertinggi terlebih dahulu.

{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
sumber
4

Python 3.x: 266 185 byte

Modifikasi langsung ke contoh program saya di pertanyaan. Perhatikan bahwa output tidak lagi diformat sehingga membutuhkan 2 tempat desimal.

Sunting: Terima kasih kepada Jo King karena membuatnya lebih kecil.

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
sumber
1
Beberapa bermain golf cepat untuk mencapai 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);}

Mengambil persentase minimum dan maksimum sebagai /100desimal (yaitu 15%sebagai 0.15).

-1 byte untuk memperbaiki masalah dengan 3.51potensi keluaran dan bermain golf cara untuk memperbaiki kesalahan pembulatan sebesar 1 byte pada saat yang sama.

Cobalah online.

Penjelasan:

(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
sumber
Saya tidak berpikir ini secara teknis valid saat ini karena pertanyaannya menentukan program, tetapi OP belum mengklarifikasi.
Surous
1
OP telah mengklarifikasi fungsi sekarang diizinkan, jadi Anda tidak perlu khawatir tentang menggandakan ukuran.
Οurous
3

Bersih , 207 156 byte

Bertukar dengan fungsi menyimpan 51 byte, tidak mengejutkan.

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

Cobalah online!

Suram
sumber
2
OP mengklarifikasi bahwa fungsi sekarang diizinkan.
Laikoni
@Laikoni Terima kasih telah memberi tahu saya :) Menghemat banyak byte - program lengkapnya mahal di Bersihkan!
Surous
2

Python ( 264 222 byte)

Sedikit lebih 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]

Cobalah secara Online!

Zachary Cotton
sumber
2

Perl 6 , 93 92 89 byte

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

Cobalah online!

Blok kode anonim yang mengambil tiga argumen (harga, persentase minimum, dan persentase maksimum) dan mengembalikan tip.

Jo King
sumber
1

Bahasa Wolfram (Mathematica) , 105 byte

Ini akan memberikan semua solusi dengan jumlah koin minimal.

MinimalBy[NumberDecompose[#,d=100{100,50,20,10,5,1,.25,.10,.05,.01}]&/@Range[Ceiling[#2#],#3#],Tr].d/100&

Cobalah online!

Kelly Lowder
sumber
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}

Cobalah online!

JohnWells
sumber
0

Jelly ,  33  32 byte

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

Tautan monadik yang menerima daftar [cost in cents, [minimum ratio, maximum ratio]]yang menghasilkan jumlah tip dalam sen.

Cobalah online!

Bagaimana?

Baris pertama adalah Tautan pembantu yang menghasilkan jumlah yang diberikan lebih sedikit dari uang kertas / koin denominasi terbesar:

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

Jumlah panggilan yang diperlukan untuk mencapai nol digunakan untuk mengurutkan kisaran jumlah tip, dan kemudian yang paling kiri dihasilkan:

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
sumber