Risparmia con l'arrotondamento dei prezzi


18

In Canada, il penny non viene più distribuito. I pagamenti in contanti sono arrotondati ai 5 centesimi più vicini.

Il denaro può essere risparmiato dividendo gli acquisti. Ad esempio, due articoli da $ 1,02 costano $ 2,04 che arrotondano a $ 2,05, ma quando si acquistano gli articoli in acquisti separati, ogni prezzo viene arrotondato a $ 1,00 per un totale di $ 2,00. Tuttavia, quando acquisti due articoli a $ 1,03 ciascuno, è meglio acquistarli in un unico acquisto.

Un altro modo per risparmiare denaro è usare una carta di credito quando l'arrotondamento è sfavorevole, perché i pagamenti del credito non sono arrotondati. Se desideriamo due articoli da $ 1,04, il prezzo totale sarà arrotondato a $ 2,10 indipendentemente da come dividiamo gli acquisti. Pertanto, dovremmo pagare per questi articoli con una carta di credito.

Scrivi una funzione o un programma che accetta un elenco di prezzi di articoli come numeri interi in centesimi e genera il prezzo totale più basso possibile (in centesimi) per quegli articoli che possono essere raggiunti attraverso una sequenza di acquisti, ciascuno in contanti o tramite credito.

Il codice più corto vince.

Casi test

[] : 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

Risposte:


5

Rubino, 119105 caratteri (93 corpi)

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

Due caratteri possono essere salvati se l'algoritmo è autorizzato a bloccarsi se alimentato con una lista della spesa vuota.


Puoi passare a s.reduce(:+)(normalmente non hai nemmeno bisogno di parentesi, ma nel tuo caso ...) e in linea mper ulteriori 2 caratteri.
Howard,

E, naturalmente a,b,c,d=(1..4).map{|i|s.count{|x|x%5==i}}.
Howard,

@Howard se rimuovo 0,dalla reducechiamata, il codice si interrompe per l'input vuoto. L'ho menzionato nella risposta. L'allineamento di m non sembra aiutare. Grazie per l'ultimo suggerimento - è stato stupido da parte mia.
John Dvorak,

1
Puoi scrivere (c-m=c>d ?d:c)che ti dà due caratteri.
Howard,

@Howard ho pensato che si sarebbe rotto perché -ha una priorità più alta di =. L'assegnazione ha una priorità alta sul lato sinistro (come in, per garantire che l'operando di sinistra sia un valore)?
John Dvorak,

5

GolfScript (54 caratteri)

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

Questo è un programma che accetta input da stdin come valori separati da spazio. Un carattere può essere salvato forzando invece il formato di input come array GolfScript.

Casi di test online

Il trucco più interessante è .2$>$per un minoperatore non distruttivo .


La mia analisi della matematica è essenzialmente la stessa di Jan e Ray: considerando i valori mod 5, l'unico risparmio è sulle transazioni del valore di 1 o 2. L'opzione carta di credito significa che non arrotondiamo mai. Quindi un articolo che costa 5n + 2 centesimi non può beneficiare del raggruppamento; né un articolo del valore di 5n + 1 centesimi (perché la combinazione di due risparmi di 1 centesimo in un risparmio di 2 centesimi non offre alcun vantaggio). 0 è l'identità additiva, quindi gli unici casi interessanti riguardano valori di 3 e 4. 3+3 = 1e 3+4 = 4+4+4 = 2; se abbiamo mischiato 3 e 4, allora ottimizziamo preferendo 3+4over 3+3(strettamente migliore) o 4+4+4(equivalente).


+1 - anche se quegli spazi sembrano così generosamente ;-) Potresti rimuoverli salvando -m ( ~):m) purtroppo senza riduzione del conteggio dei caratteri.
Howard,

@Howard, lo so, l'ho provato anche io. : D
Peter Taylor,

3

C ++: 126 caratteri

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

Benvenuti a dare una guida per mettere questo programma più breve. Ecco il programma di test, compilare con il compilatore tdm-gcc 4.7.1 ed eseguire normalmente.

#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;
}

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))))

Test (dove Pè un alias per il codice sopra)

> 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

1

Mathematica 112 126 167 157

Modifica : Casi di {3, 3} e {4,4,4} ora gestiti grazie a Peter Taylor e cartone_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]]

Nota: i non acquisti (caso di test n. 1) vengono inseriti come f[{0}].

Come funziona

  1. Per ogni articolo, il massimo multiplo di 5 in meno del rispettivo prezzo verrà pagato indipendentemente dalla forma di pagamento. (Non ci si può aggirare.)
  2. I resti di Mod[n, 5]vengono quindi elaborati: 1 e 2 diventano 0. Gli zeri rimangono invariati.
  3. Ogni coppia {3, 4} -> {5}; successivamente ogni coppia {3, 3} -> {5}; quindi la tripla, {4,4,4} -> {10}, se applicabile.
  4. I restanti 4, se presenti, rimangono invariati (pagati con carta di credito).
  5. I multipli originali di 5 sono stati sommati con i resti che sono stati modificati (o meno) nei passaggi da (2) a (4).

analisi

a12regola per {3,3} a13regola per {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}


1
Che dire di {3,3}?
Peter Taylor,

@PeterTaylor. Buon punto. È scivolato vicino.
DavidC

Che dire di {4,4,4}? Penso che con {3,4} -> {5}, {3,3} -> {5} e {4,4,4} -> {10} (in questo ordine) dovrebbe dare risposte ottimali.
cardboard_box

@cardboard_box Hai ragione! Vedi aggiornamento
DavidC,

Ho aggiunto altri casi di test alla domanda. Quelli che avevo sono stati generati casualmente in modo che quei casi angolari non si presentassero.
cardboard_box

1

Python 3 (115 caratteri)

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 caratteri)

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

2
La domanda richiede il prezzo totale, quindi dovrebbe esserci un output per l'intero elenco. Ad esempio, l'input [3,4,9]dovrebbe dare 14, perché è possibile combinare gli articoli da 3 e 4 centesimi per ottenere un acquisto di 7 centesimi che si paga in contanti con 5 centesimi e l'oggetto rimanente da 9 centesimi che si paga con credito perché altrimenti arrotonderebbe.
cardboard_box

2
Dato 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, questo dà 0.0, 0.0, 2.5, 3.33, 5.0, 5.0, 5.0, 7.5, 8.33, 10.0, che somma a 46.66. Tuttavia, la risposta corretta è 45, quindi la somma dei numeri stampati non è la risposta corretta, e quindi questa soluzione non è corretta.
Nolen Royalty,

Questa risposta è stata scritta quando il lavoro non contiene ancora "totale"
AMK,

2
Temo di dover raccomandare la cancellazione. Asker non ha modificato i requisiti, li ha chiariti. Se il prezzo di ciascun articolo è stato desiderato separatamente, allora perché la menzione di una "sequenza di acquisti / acquisto singolo" e la discussione su quale sia favorevole?
John Dvorak,

Cancella le risposte sbagliate. Ora è la risposta più breve di Python
AMK,

0

APL, 58 caratteri

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

Il programma è essenzialmente una traduzione diretta della soluzione Ruby di 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

è il vettore vuoto.


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

spiegazione:

In un acquisto, puoi risparmiare al massimo 2 centesimi. Quindi, se hai una combinazione che può farti risparmiare 2 centesimi, acquistalo in quel modo e sarà ottimale . Ad esempio, se hai xarticoli con prezzo 3 (mod 5) e yarticoli con prezzo 4 (mod 5), puoi creare un min(x, y)numero di (3, 4) coppie, che ti fanno risparmiare 2 min(x, y)centesimi. Quindi usi gli altri 3, se presenti, per risparmiare max(0, x-min(x,y)) / 2centesimi. Questo può anche essere calcolato da(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

modificare

Questa soluzione è sbagliata.


+1 per l'utilizzo di una lingua relativamente sconosciuta che potrebbe essere interessante da imparare
John Dvorak,

È una nuova lingua in fase di sviluppo attivo. Combina molti punti di forza di lingue diverse. Spero che più persone possano saperlo.
Ray

L'analisi non è abbastanza completa, perché se hai 4 4 4 3 3allora 4 4 4è una combinazione che può risparmiare 2 centesimi, ma acquistarla in questo modo non è ottimale. (In effetti, sembra che non ti stia prendendo 4 4 4in considerazione affatto. Questo codice non fallisce l'ultimo caso di test?)
Peter Taylor
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.