Ahorre dinero con redondeo de precios

18

En Canadá, el centavo ya no circula. Los pagos en efectivo se redondean a los 5 centavos más cercanos.

El dinero se puede ahorrar dividiendo las compras. Por ejemplo, dos artículos de $ 1.02 cuestan $ 2.04, que se redondean a $ 2.05, pero al comprar los artículos en compras separadas, cada precio se redondea a $ 1.00 por un total de $ 2.00. Sin embargo, al comprar dos artículos a $ 1.03 cada uno, es mejor comprarlos en una sola compra.

Otra forma de ahorrar dinero es usar una tarjeta de crédito cuando el redondeo es desfavorable, porque los pagos de crédito no son redondeados. Si queremos dos artículos de $ 1.04, el precio total se redondeará a $ 2.10 independientemente de cómo dividimos las compras. Por lo tanto, debemos pagar estos artículos con una tarjeta de crédito.

Escriba una función o programa que acepte una lista de precios de artículos como enteros en centavos y genere el precio total más bajo posible (en centavos) para aquellos artículos que se pueden lograr a través de una secuencia de compras, ya sea en efectivo o con crédito.

El código más corto gana.

Casos de prueba

[] : 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
caja de cartón
fuente

Respuestas:

5

Ruby, 119105 caracteres (93 cuerpos)

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

Se pueden guardar dos caracteres si se permite que el algoritmo se bloquee al alimentar una lista de compras vacía.

John Dvorak
fuente
Puede cambiar a s.reduce(:+)(normalmente incluso no necesita paréntesis, pero en su caso ...) y en línea mpara 2 caracteres adicionales.
Howard
Y, por supuesto a,b,c,d=(1..4).map{|i|s.count{|x|x%5==i}}.
Howard
@Howard si elimino 0,de la reducellamada, el código se rompe para la entrada vacía. Mencioné eso en la respuesta. Inline m no parece ayudar. Gracias por la última sugerencia, fue una estupidez de mi parte.
John Dvorak,
1
Puedes escribir lo (c-m=c>d ?d:c)que te da dos caracteres.
Howard
@Howard pensé que se rompería porque -tiene mayor prioridad que =. ¿Es que la asignación tiene una alta prioridad en su lado izquierdo (como en, para garantizar que el operando izquierdo sea un valor)?
John Dvorak,
5

GolfScript (54 caracteres)

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

Este es un programa que toma la entrada de stdin como valores separados por espacios. Un carácter podría guardarse forzando el formato de entrada para que sea como matrices de GolfScript.

Casos de prueba en línea

El truco más interesante es .2$>$para un minoperador no destructivo .


Mi análisis de las matemáticas es esencialmente el mismo que el de Jan y Ray: considerando los valores mod 5, el único ahorro es en transacciones con valor de 1 o 2. La opción de tarjeta de crédito significa que nunca redondeamos. Por lo tanto, un artículo que cuesta 5n + 2 centavos no puede beneficiarse de la agrupación; ni un artículo que valga 5n + 1 centavos (porque combinar dos ahorros de 1 centavo en un ahorro de 2 centavos no da ningún beneficio). 0 es la identidad aditiva, por lo que los únicos casos interesantes involucran valores de 3 y 4. 3+3 = 1y 3+4 = 4+4+4 = 2; Si hemos mezclado 3s y 4s, entonces optimizamos al preferir 3+4sobre 3+3(estrictamente mejor) o 4+4+4(equivalente).

Peter Taylor
fuente
+1 - aunque esos espacios se ven tan lujosamente ;-) Puede eliminarlos guardando -m ( ~):m) desafortunadamente sin reducción en el recuento de caracteres.
Howard
@Howard, lo sé, también lo intenté. : D
Peter Taylor
3

C ++: 126 caracteres

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

Bienvenido a dar orientación para que este programa se acorte. Aquí está el programa de prueba, compile con el compilador tdm-gcc 4.7.1 y ejecútelo 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;
}
jie
fuente
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))))

Pruebas (donde Phay un alias para el código anterior)

> 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
fuente
1

Mathematica 112 126 167 157

Editar : los casos de {3, 3} y {4,4,4} ahora se manejan gracias a Peter Taylor y cartón_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: No compras (caso de prueba # 1) se ingresan como f[{0}].

Cómo funciona

  1. Para cada artículo, se pagará el mayor múltiplo de 5 menos que el precio respectivo, independientemente de la forma de pago. (No evitar eso)
  2. El resto de Mod[n, 5]se procesa: 1 y 2 se convierten en 0. Los ceros permanecen sin cambios.
  3. Cada par {3, 4} -> {5}; luego cada par {3, 3} -> {5}; entonces el triple, {4,4,4} -> {10}, si corresponde.
  4. Los 4 restantes, si corresponde, permanecen sin cambios (pagados con tarjeta de crédito).
  5. Los múltiplos originales de 5 sumados con los restos que fueron ajustados (o no) en los pasos (2) a (4).

Pruebas

a12se ajusta para {3,3} se a13ajusta para {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
fuente
1
¿Qué pasa con {3,3}?
Peter Taylor
@PeterTaylor. Buen punto. Se deslizó por.
DavidC
¿Qué pasa con {4,4,4}? Creo que con {3,4} -> {5}, {3,3} -> {5} y {4,4,4} -> {10} (en ese orden) debería dar respuestas óptimas.
caja de cartón
@cardboard_box ¡Tienes razón! Ver actualización.
DavidC
Agregué sus casos de prueba adicionales a la pregunta. Los que tenía se generaron al azar para que esos casos de esquina no aparecieran.
caja de cartón
1

Python 3 (115 caracteres)

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

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
fuente
2
La pregunta solicita el precio total, por lo que debe haber una salida para toda la lista. Por ejemplo, la entrada [3,4,9]debería dar 14, porque puede combinar los artículos de 3 y 4 centavos para obtener una compra de 7 centavos que paga en efectivo con 5 centavos, y el artículo restante de 9 centavos que paga con crédito porque de lo contrario se redondearía.
caja de cartón
2
Dado 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, esto da 0.0, 0.0, 2.5, 3.33, 5.0, 5.0, 5.0, 7.5, 8.33, 10.0, lo que suma 46.66. Sin embargo, la respuesta correcta es 45, por lo que la suma de los números que imprime no es la respuesta correcta y, por lo tanto, esta solución es incorrecta.
Nolen Royalty
Esta respuesta se escribió cuando el trabajo aún no contiene "total"
AMK
2
Me temo que tengo que recomendar la eliminación. Asker no cambió los requisitos, los aclaró. Si se desea el precio de cada artículo por separado, ¿por qué mencionar una "secuencia de compras / compra única" y la discusión de cuál es favorable?
John Dvorak
Borro las respuestas incorrectas. Ahora es la respuesta más corta de Python
AMK
0

APL, 58 caracteres

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

El programa es esencialmente una traducción directa de la solución Ruby de 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

Es el vector vacío.

Volatilidad
fuente
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

Explicación:

En una compra, puede ahorrar 2 centavos como máximo. Entonces, si tiene una combinación que puede ahorrarle 2 centavos, simplemente cómprela de esa manera y será óptima . Por ejemplo, si tiene xartículos con precio 3 (mod 5) y yartículos con precio 4 (mod 5), puede hacer un min(x, y)número de (3, 4) pares, lo que le ahorrará 2 min(x, y)centavos. Luego usas los 3 restantes, si los hay, para ahorrarte max(0, x-min(x,y)) / 2centavos. Esto también se puede calcular por(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

Editar

Esta solución está mal.

Rayo
fuente
+1 por usar un idioma relativamente desconocido que podría ser interesante de aprender
John Dvorak
Es un nuevo lenguaje en desarrollo activo. Combina muchas fuerzas de diferentes idiomas. Espero que más personas puedan saberlo.
Ray
El análisis no es del todo completo, porque si lo tiene, 4 4 4 3 3entonces 4 4 4es una combinación que puede ahorrar 2 centavos, pero comprarlo de esa manera no es óptimo. (De hecho, no parece estar teniendo 4 4 4en cuenta en absoluto. ¿No falla este código en el último caso de prueba?)
Peter Taylor