Hemat uang dengan pembulatan harga

18

Di Kanada, sen tidak lagi diedarkan. Pembayaran tunai dibulatkan ke 5 sen terdekat.

Uang dapat dihemat dengan memisahkan pembelian. Sebagai contoh, dua item $ 1,02 berharga $ 2,04 yang membulatkan hingga $ 2,05, tetapi ketika membeli item dalam pembelian terpisah, masing-masing putaran harga menjadi $ 1,00 dengan total $ 2,00. Namun, ketika membeli dua item masing-masing dengan $ 1,03, lebih baik membelinya dalam satu pembelian.

Cara lain untuk menghemat uang adalah menggunakan kartu kredit ketika pembulatan tidak menguntungkan, karena pembayaran kredit tidak dibulatkan. Jika kita menginginkan dua item $ 1,04, total harga akan mencapai $ 2,10 terlepas dari bagaimana kita membagi pembelian. Karena itu, kita harus membayar barang-barang ini dengan kartu kredit.

Tulis fungsi atau program yang menerima daftar harga barang sebagai bilangan bulat dalam sen dan output harga total serendah mungkin (dalam sen) untuk barang-barang yang dapat dicapai melalui urutan pembelian, masing-masing baik secara tunai atau kredit.

Kode terpendek menang.

Uji kasus

[] : 0
[48] : 48
[92, 20] : 110
[47, 56, 45] : 145
[55, 6, 98, 69] : 225
[6, 39, 85, 84, 7] : 218
[95, 14, 28, 49, 41, 39] : 263
[92, 6, 28, 30, 39, 93, 53] : 335
[83, 33, 62, 12, 34, 29, 18, 12] : 273
[23, 46, 54, 69, 64, 73, 58, 92, 26] : 495
[19, 56, 84, 23, 20, 53, 96, 92, 91, 58] : 583
[3, 3, 19, 56, 3, 84, 3, 23, 20, 53, 96, 92, 91, 58, 3, 3] : 598
[2, 3, 4, 4, 4, 4, 4] : 19
kotak kardus
sumber

Jawaban:

5

Ruby, 119 105 karakter (93 tubuh)

def f s
a,b,c,d=(1..4).map{|i|s.count{|x|x%5==i}}
s.reduce(0,:+)-a-(c-m=c>d ?d:c)/2-2*(b+m+(d-m)/3)
end

Dua karakter dapat disimpan jika algoritme dibiarkan mogok saat diberi daftar belanja kosong.

John Dvorak
sumber
Anda dapat mengubah ke s.reduce(:+)(biasanya Anda bahkan tidak perlu paranthes, tetapi dalam kasus Anda ...) dan sebaris muntuk 2 karakter tambahan.
Howard
Dan tentu saja a,b,c,d=(1..4).map{|i|s.count{|x|x%5==i}}.
Howard
@ Bagaimana jika saya menghapus 0,dari reducepanggilan, kode istirahat untuk input kosong. Saya memang menyebutkan itu dalam jawabannya. Inlining m sepertinya tidak membantu. Terima kasih atas saran terakhir - itu bodoh dari saya.
John Dvorak
1
Anda dapat menulis (c-m=c>d ?d:c)yang memberi Anda dua karakter.
Howard
@Howard Saya pikir itu akan pecah karena -memiliki prioritas lebih tinggi daripada =. Apakah tugas itu memiliki prioritas tinggi di sisi kirinya (seperti pada, untuk memastikan operan kiri adalah nilai lebih)?
John Dvorak
5

GolfScript (54 karakter)

~]4,{){\5%=}+1$\,,}%~.2$>$:m- 3/m+@+2*@@m- 2/++~)+{+}*

Ini adalah program yang mengambil input dari stdin sebagai nilai yang dipisahkan oleh ruang. Satu karakter dapat disimpan dengan memaksa format input bukan sebagai array GolfScript.

Uji kasus secara online

Trik yang paling menarik adalah .2$>$untuk minoperator yang tidak merusak .


Analisis matematika saya pada dasarnya sama dengan analisis Jan dan Ray: mengingat nilai mod 5, satu-satunya penghematan adalah pada transaksi bernilai 1 atau 2. Opsi kartu kredit berarti bahwa kita tidak pernah berhasil. Jadi item yang harganya 5n + 2 sen tidak bisa mendapatkan keuntungan dari bundling; item tidak dapat bernilai 5n + 1 sen (karena menggabungkan dua tabungan 1 sen ke dalam tabungan 2 sen tidak memberikan manfaat apa pun). 0 adalah identitas aditif, jadi satu-satunya kasus yang menarik melibatkan nilai 3 dan 4. 3+3 = 1dan 3+4 = 4+4+4 = 2; jika kita memiliki 3s campuran dan 4s kemudian kita mengoptimalkan oleh lebih memilih 3+4lebih 3+3(ketat baik) atau 4+4+4(setara).

Peter Taylor
sumber
+1 - meskipun ruang-ruang tersebut terlihat sangat mewah ;-) Anda mungkin menghapusnya dengan menyimpan -m ( ~):m) sayangnya tanpa pengurangan dalam jumlah char.
Howard
@ Howard, saya tahu, saya juga mencobanya. : D
Peter Taylor
3

C ++: 126 karakter

int P(int*m,int i){int t=0,h=0,d;while(i>-1){d=m[i]%5;t+=m[i--];d<3?t-=d:d==4?h++,t-=2:h--;}h<0?t+=h/2:t+=(h-h/3)*2;return t;}

Selamat memberikan panduan untuk membuat program ini menjadi lebih pendek. Berikut adalah program pengujian, kompilasi dengan tdm-gcc 4.7.1 compiler dan jalankan secara normal.

#include<iostream>
using namespace std;

//m[i]表示单个商品的价格,t表示所有商品总价格,
//d为单个商品价格取模后的值,h为单个商品价格取模后值为3的个数,
//f为单个商品价格取模后值为4的个数
int P(int*m,int i){int t=0,h=0,d;while(i>-1){d=m[i]%5;t+=m[i--];d<3?t-=d:d==4?h++,t-=2:h--;}h<0?t+=h/2:t+=(h-h/3)*2;return t;}

int main() {
int p1[1]={48};
int p2[2]={92,20};
int p3[3]={47,56,45};
int p4[4]={55,6,98,69};
int p5[5]={6,39,85,84,7};
int p6[6]={95,14,28,49,41,39};
int p7[7]={92,6,28,30,39,93,53};
int p8[8]={83,33,62,12,34,29,18,12};
int p9[9]={23,46,54,69,64,73,58,92,26};
int p10[10]={19,56,84,23,20,53,96,92,91,58};
int p11[10]={1,2,3,4,5,6,7,8,9,10};
cout<<P(p1,0)<<endl
    <<P(p2,1)<<endl
    <<P(p3,2)<<endl
    <<P(p4,3)<<endl
    <<P(p5,4)<<endl
    <<P(p6,5)<<endl
    <<P(p7,6)<<endl
    <<P(p8,7)<<endl
    <<P(p9,8)<<endl
    <<P(p10,9)<<endl
    <<P(p11,9)<<endl;

return 0;
}
jie
sumber
1

R 143

function(x)min(sapply(rapply(partitions::listParts(length(x)),
                             function(i)min(sum(x[i]),5*round(sum(x[i])/5)),h="l"),
                      function(x)sum(unlist(x))))

Tes (di mana Palias untuk kode di atas)

> P(c(48))
[1] 48
> P(c(92, 20))
[1] 110
> P(c(47, 56, 45))
[1] 145
> P(c(55, 6, 98, 69))
[1] 225
> P(c(6, 39, 85, 84, 7))
[1] 218
> P(c(95, 14, 28, 49, 41, 39))
[1] 263
> P(c(92, 6, 28, 30, 39, 93, 53))
[1] 335
> P(c(83, 33, 62, 12, 34, 29, 18, 12))
[1] 273
> P(c(23, 46, 54, 69, 64, 73, 58, 92, 26))
[1] 495
> P(c(19, 56, 84, 23, 20, 53, 96, 92, 91, 58))
[1] 583
flodel
sumber
1

Mathematica 112 126 167 157

Sunting : Kasing {3, 3} dan {4,4,4} sekarang ditangani berkat Peter Taylor dan cardboard_box.

n_~g~o_ := {a___, Sequence @@ n, b___} :> {a, b, o};
f@s_ := Tr@Join[#[[2]], Sort@#[[1]] //. {1 -> 0, 2 -> 0, g[{3, 4}, 5], g[{3, 3}, 5], 
   g[{4, 4, 4}, 10]}] &[Transpose[{m = Mod[#, 5], # - m} & /@ s]]

Catatan: Non-pembelian (test case # 1) dimasukkan sebagai f[{0}].

Bagaimana itu bekerja

  1. Untuk setiap item, kelipatan terbesar 5 kurang dari harga masing-masing akan dibayarkan terlepas dari bentuk pembayaran. (Tidak menyiasati itu.)
  2. Sisanya Mod[n, 5]kemudian diproses: 1's dan 2's menjadi 0's. Nol tetap tidak berubah.
  3. Setiap pasangan {3, 4} -> {5}; setelah itu setiap pasangan {3, 3} -> {5}; kemudian rangkap tiga, {4,4,4} -> {10}, jika berlaku.
  4. 4 sisanya, jika ada, tetap tidak berubah (dibayar dengan kartu kredit).
  5. Kelipatan asli dari 5 dijumlahkan dengan sisa yang di-tweak (atau tidak) dalam langkah (2) hingga (4).

Pengujian

a12menyesuaikan untuk {3,3} a13menyesuaikan untuk {4,4,4}

a1={0};
a2={48};
a3={92,20};
a4={47,56,45};
a5={55,6,98,69} ;
a6={6,39,85,84,7};
a7={95,14,28,49,41,39};
a8={92,6,28,30,39,93,53};
a9={83,33,62,12,34,29,18,12};
a10={23,46,54,69,64,73,58,92,26};
a11={19,56,84,23,20,53,96,92,91,58};
a12={3,3,19,56,3,84,3,23,20,53,96,92,91,58,3,3};
a13={2,3,4,4,4,4,4};

f /@ {a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13}

{0, 48, 110, 145, 225, 218, 263, 335, 273, 495, 583, 598, 19}

DavidC
sumber
1
Bagaimana dengan {3,3}?
Peter Taylor
@PeterTaylor. Poin bagus. Itu lewat.
DavidC
Bagaimana dengan {4,4,4}? Saya pikir dengan {3,4} -> {5}, {3,3} -> {5} dan {4,4,4} -> {10} (dalam urutan itu) harus memberikan jawaban yang optimal.
cardboard_box
@ cardboard_box Anda benar! Lihat pembaruan.
DavidC
Saya menambahkan kasus uji tambahan Anda ke pertanyaan. Yang saya punya dihasilkan secara acak sehingga kasus-kasus sudut tidak muncul.
cardboard_box
1

Python 3 (115 karakter)

m=eval(input());t=a=b=0
for v in m:d=v%5;t+=v-d*(d<3);a+=d==3;b+=d==4
d=min(a,b);a-=d;b-=d;print(t-d*2-a//2-b//3*2)

Python 2 (106 karakter)

m=input();t=a=b=0
for v in m:d=v%5;t+=v-d*(d<3);a+=d==3;b+=d==4
d=min(a,b);a-=d;b-=d;print t-d*2-a/2-b/3*2
AMK
sumber
2
Pertanyaannya menanyakan harga total, jadi harus ada satu output untuk seluruh daftar. Misalnya, input [3,4,9]harus diberikan 14, karena Anda dapat menggabungkan item 3 dan 4 sen untuk mendapatkan pembelian 7 sen yang Anda bayar tunai dengan 5 sen, dan sisa item 9 sen yang Anda bayar dengan kredit karena jika tidak maka akan dibulatkan.
cardboard_box
2
Diberikan 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ini memberi 0.0, 0.0, 2.5, 3.33, 5.0, 5.0, 5.0, 7.5, 8.33, 10.0, yang merupakan jumlah 46.66. Namun, jawaban yang benar adalah 45, jadi jumlah angka yang Anda cetak bukanlah jawaban yang benar, dan karenanya solusi ini salah.
Nolen Royalty
Jawaban ini ditulis ketika pekerjaan belum mengandung "total"
AMK
2
Saya khawatir saya harus merekomendasikan penghapusan. Penanya tidak mengubah persyaratan - dia menjelaskannya. Jika harga untuk setiap item secara terpisah diinginkan, lalu mengapa penyebutan "urutan pembelian / pembelian tunggal" dan diskusi yang mana yang menguntungkan?
John Dvorak
Saya menghapus jawaban yang salah. Sekarang Ini jawaban Python terpendek
AMK
0

APL, 58 karakter

{a b c d←+/(⍳4)∘.=5|⍵⋄(+/⍵)-a-(⌊2÷⍨c-m)-2×b+m+⌊3÷⍨d-m←c⌊d}

Program ini pada dasarnya adalah terjemahan langsung dari solusi Ruby Jan Dvorak .


      {a b c d←+/(⍳4)∘.=5|⍵⋄(+/⍵)-a-(⌊2÷⍨c-m)-2×b+m+⌊3÷⍨d-m←c⌊d}⍬
0
      {a b c d←+/(⍳4)∘.=5|⍵⋄(+/⍵)-a-(⌊2÷⍨c-m)-2×b+m+⌊3÷⍨d-m←c⌊d}95 14 28 49 41 39
263
      {a b c d←+/(⍳4)∘.=5|⍵⋄(+/⍵)-a-(⌊2÷⍨c-m)-2×b+m+⌊3÷⍨d-m←c⌊d}19 56 84 23 20 53 96 92 91 58
583

adalah vektor kosong.

Keriangan
sumber
0

Julia 83C

C=L->let
w,z,x,y=map(i->[i==x%5for x=L]|sum,1:4)
L|sum-(x+2w+3min(x,y)+4z)>>1
end

Penjelasan:

Dalam satu pembelian, Anda dapat menyimpan paling banyak 2 sen. Jadi, jika Anda memiliki kombinasi yang dapat menghemat 2 sen, beli saja dengan cara itu dan itu akan menjadi optimal . Misalnya, jika Anda memiliki xitem dengan harga 3 (mod 5) dan yitem dengan harga 4 (mod 5), Anda dapat membuat min(x, y)jumlah (3, 4) pasangan, yang menghemat Anda 2 min(x, y)sen. Kemudian Anda menggunakan 3 sisanya, jika ada, untuk menghemat max(0, x-min(x,y)) / 2sen Anda . Ini juga dapat dihitung dengan(max(x,y)-y)/2

w = sum(1 for p in prices if p % 5 == 1)
z = sum(1 for p in prices if p % 5 == 2)
x = sum(1 for p in prices if p % 5 == 3)
y = sum(1 for p in prices if p % 5 == 4)

ans = sum(prices) - (w + 2 z + 2 min(x, y) + div(max(x, y) - y, 2))
    = sum(prices) - (2w + 4z + 4 min(x, y) + x + y - min(x, y) - y) `div` 2
    = sum(prices) - (2w + 4z + 3 min(x, y) + x) `div` 2

Edit

Solusi ini salah.

sinar
sumber
+1 untuk menggunakan bahasa yang relatif tidak dikenal yang mungkin menarik untuk dipelajari
John Dvorak
Ini adalah bahasa baru dalam pengembangan aktif. Ini menggabungkan banyak kekuatan dari berbagai bahasa. Semoga lebih banyak orang bisa mengetahuinya.
Ray
Analisis ini tidak cukup lengkap, karena jika Anda memiliki 4 4 4 3 3kemudian 4 4 4adalah kombinasi yang dapat menghemat 2 sen, tetapi membeli dengan cara yang tidak optimal. (Sebenarnya, Anda tampaknya tidak 4 4 4mempertimbangkan sama sekali. Bukankah kode ini gagal dalam ujian terakhir?)
Peter Taylor