El Algoritmo del Cajero es un algoritmo para realizar cambios en la cantidad mínima de monedas que funciona bastante bien para la mayoría de los sistemas monetarios. Sin embargo, como la mayoría de los algoritmos codiciosos, no está exento de defectos. Si un sistema monetario está configurado correctamente (o simplemente incorrecto), hay ciertos valores en los cuales el Algoritmo del Cajero no podrá encontrar el cambio óptimo.
Tome el siguiente ejemplo:
Tenemos monedas de 4 ¢, 3 ¢ y 1 ¢. Queremos hacer 6 ¢.
El algoritmo del cajero seleccionará primero la mayor cantidad de monedas (una de 4 ¢ para comenzar) y restará y repetirá. Esto dará como resultado una moneda de 4 ¢ y dos monedas de 1 ¢, para un total de 3 monedas.
Desafortunadamente para el Algoritmo hay una manera de hacer 6 ¢ con solo dos monedas (dos monedas de 3 ¢).
Un sistema de cambio se considerará canónico si para todos los valores enteros el Algoritmo del Cajero encontrará la cantidad óptima de monedas.
Tarea
Su tarea será tomar un sistema como un contenedor no ordenado o un contenedor ordenado ordenado de enteros que representan valores de monedas y generar un valor verdadero si la entrada del sistema es canónica y falsa de lo contrario.
Su programa debería funcionar para todos los sistemas que puedan crear cualquier valor. (es decir, todos los sistemas tendrán una moneda de 1 ¢)
Este es el código de golf menos bytes gana.
Casos de prueba
Esta lista no es exhaustiva, su programa debería funcionar para todas las entradas válidas
1, 3, 4 -> 0
1, 5, 10, 25 -> 1
1, 6, 10, 25 -> 0
1, 2, 3 -> 1
1, 8, 17, 30 -> 0
1, 3, 8, 12 -> 0
1, 2, 8, 13 -> 0
1, 2, 4, 6, 8 -> 1
fuente
25, 9, 4, 1
(de esta publicación de matemáticas. SE ), aunque cada moneda es más grande que la suma de las más pequeñas, la no codiciosa25, 4, 4, 4
vence a la codiciosa25, 9, 1, 1, 1
.9, 4, 1
->4, 4, 4
ser mejor que9, 1, 1, 1
es un ejemplo más estricto.Respuestas:
Haskell,
948782 bytesesta solución funciona definiendo una función
j
que realiza el algoritmo del cajero y nos dice cuántas monedas usó el cajero. luego verificamos hasta el doble del número más grande en la lista, suponiendo que el sistema ha sido canónico para todos los números anteriores, que tomar la moneda más grande posible es la opción correcta.Esta solución supone que la entrada está ordenada.
la comprobación de pruebas hasta el doble del número más grande es suficiente: suponga que el sistema no es canónico para algún número
i
, y dejek
que el número más grande en la lista no sea mayori
. suponga esoi >= 2k
y el sistema es canónico para todos los números menores quei
.tome una forma óptima de hacer
i
monedas y suponga que no contiene la monedak
. si tiramos una de las monedas, la nueva suma de monedas debe ser mayork
y menor quei
, pero el algoritmo del cajero en este número usaría lak
moneda, y por lo tanto, este conjunto de monedas se puede reemplazar con un conjunto igual de monedas que contiene la monedak
y, por lo tanto, hay un conjunto de monedas que contiene la monedak
para el númeroi
y, por inducción, el algoritmo del cajero devuelve la opción óptima.Este argumento realmente muestra que solo necesitamos verificar hasta la suma de los dos elementos más grandes, pero es más largo hacerlo.
Editar: cinco bytes de descuento gracias a Ørjan Johansen!
fuente
let
lugar dewhere
. Puede colocarlo como un|let ...
patrón de protección despuésf s
o dentro de la lista de comprensión.j i=last$0:[1+j(i-k)|k<-s,k<i]
.Pyth,
1815 bytesBanco de pruebas
Un tipo diferente de fuerza bruta. Esto comienza formando todas las colecciones de monedas con hasta k de cada una, donde k es la moneda más grande, que se supone que es la última moneda. Creo que esto siempre es suficiente para formar dos juegos de monedas con la misma suma, una codiciosa y otra más corta, siempre que exista tal par.
Luego ubico un par de este modo:
Los subconjuntos se generan en orden de tamaño creciente, y lexicográficamente por posición en la entrada secundaria. Agrupe las colecciones de monedas por sumas, de manera estable. Cada colección de monedas se genera en orden descendente, por lo que la solución codiciosa será el primer elemento del grupo si y solo si la solución codiciosa es óptima, y será el último elemento del grupo lexicográficamente. Por lo tanto, encontramos la solución codiciosa y filtramos en un índice distinto de cero en el grupo. Si el conjunto de monedas es canónico, esto filtrará todo, por lo que simplemente negamos lógicamente el resultado y la salida.
Explicación:
fuente
/opt/tryitonline/bin/pyth: line 5: 28070 Killed ... Exit code: 137
en TIO? ¿Solo de memoria?PHP, 323 bytes
Del mismo modo que otros, cuente las monedas hasta la suma de los dos últimos elementos de la matriz
Mi mejor y más larga respuesta creo> 370 Bytes
Solo doy una versión ampliada porque es más larga que mi respuesta antes
Explicación de esta respuesta.
Versión en línea
Establezca todo en la matriz en falso == X
Establezca todos los números en la matriz que controla en S
Se encontraron diferencias entre la última S y la otra S o 0
Comience en la última S en la matriz
Establezca todos los números en D donde última S + una de todas las diferencias
Comience en todo D
SET "T" a los valores D en la matriz
GOTO 5 Repítalo con todos los DI encontrados, realmente no lo hizo en el código
Si el siguiente elemento de la matriz tiene X, es un caso falso, de lo contrario es verdadero
Pasos adicionales La diferencia está en el caso en el fragmento 3 Entre 1 y 4 son 2 X Esto significa que necesita la segunda D en el Paso 5. Después de este valor en este caso 10 son todos los casos verdaderos que pude ver hasta ahora que hay una relación entre la diferencia y la cuenta en la matriz que controlas para calcular cuánto D (Paso 5) necesitas para obtener el punto antes de encontrar el último caso falso.
Establece varios valores desde el último elemento directamente a verdadero. Estos puntos pueden marcar la diferencia para decidir si podría ser que el codicioso conteo de monedas con el siguiente valor sea el mismo que el múltiplo de los últimos en la matriz. Por otro lado puedes establecer enemigo
Establecer primer enemigo en 1 + Última S
Desde este punto, agregue cada valor en la matriz para establecer los siguientes enemigos
Comience con el último enemigo Goto 2
Si ahora tiene enemigos y casos verdaderos, aumenta la probabilidad de que los recuentos puedan ser los mismos. Con más D, la probabilidad disminuye.
más? Bytes Gracias @ JonathanAllan por darme casos de prueba incorrectos
262 Bytes Casi pero no lo suficientemente bueno 4 casos de prueba incorrectos en el momento
casos de prueba [1,16,256] antes debe ser verdadero después de falso
Orden ascendente de la matriz
Explicación
Parece que lo que he visto en la tabla contiene valores de [1,2,3,4,5,6] y solo cambio el último elemento hasta 9. Para 2to3 y 4to5 creamos el valor del valor más bajo en cálculo de módulo
fuente
", "
cuando puedes dividirte","
? ¿Por qué te separas cuando puedes tomar una lista? ¿Por qué clasificas cuando puedes tomar una lista ordenada? (Todavía no estoy seguro si el método que está utilizando es infalible, tenga una prueba, porque la literatura que he leído parece sugerir que es más difícil de lo que creo que está haciendo su código).[1,2,5,11,17]
es canónico. Tal vez eche un vistazo al papel vinculado en mi respuesta.JavaScript (ES6), 116
125 130Esto necesita la matriz de entrada ordenada en orden descendente. Para cada valor de 2N downto 2 (N es el valor máximo de la moneda), encuentra el número de monedas del algoritmo codicioso e intenta encontrar un conjunto más pequeño de monedas.
Menos golf
Prueba
fuente
Python,
218 211205 bytes-1 byte gracias a @TuukkaX (se puede eliminar un espacio entre
<3
yor
)repl.it
Entrada en orden descendente.
Horriblemente fuerza bruta. Cualquier conjunto de monedas de una sola unidad y alguna otra moneda es canónico. Para conjuntos más grandes, el caso de falla más pequeño, si existe, será mayor o igual que la tercera moneda más pequeña (¡no estoy seguro de cómo podría ser igual!) Y menor que la suma de las dos monedas más grandes; vea este documento (que en realidad hace referencia a otro pero también da un método O (n ^ 3)).
g
cuenta las monedas utilizadas por el método codicioso, y la función sin nombre atraviesa los posibles candidatos (en realidad, de 0 a una menos del doble de la moneda más grande para ahorrar bytes) y busca cualquier colección de menos monedas que también sumen esa cantidad.g
funciona mediante la realización de un cajero lo haría, de forma recursiva toma la moneda más grande menor o igual al importe que aún conforman,[v for v in c if v<=x][0]
de distancia, y llega hasta el número de monedas utilizadas,n
.La función sin nombre devuelve 1 si
len(c)
es menor que 3, y de lo contrario prueba que no es el caso,1-...
que cualquier valor en el rango de posibilidadesrange(c[0]*2)))
, es posible con menos monedasi in range(g(x,c))
, al hacer una colección de esa cantidad de cada moneda,c*i
y examinando todas las combinaciones dei
monedas,combinations(c*i,i)
para ver si alguna suma al mismo valor.fuente
3or
Deberia trabajar.not(...)
con1-...
Gelatina ( tenedor ),
1514 bytesEsta solución utiliza los límites para contraejemplos de este documento . Allí, el autor utiliza un límite estricto para el contraejemplo, pero en interés del golf, se utiliza el rango de la suma de las denominaciones de monedas que es más grande y contiene ese límite.
Este programa calcula todos los casos de prueba en menos de un segundo en mi máquina.
Desafortunadamente, esto se basa en una rama de Jelly donde estaba trabajando en la implementación de un átomo de solución de Frobenius para que no pueda probarlo en línea.
Uso
El rendimiento es bueno y puede resolver todos los casos de prueba a la vez en menos de un segundo.
Explicación
fuente
JavaScript (ES6),
144132124122110 bytesRequiere que la matriz se ordene en orden descendente. Utiliza la observación en el documento vinculado de que si el sistema no es canónico, entonces hay al menos un valor menor que 2a [0] que toma menos monedas cuando se descompone usando las monedas no utilizadas del algoritmo codicioso inicial.
Editar: ahorré 12 bytes al darme cuenta de que podía verificar todas las monedas a pesar de que ya había alcanzado el valor objetivo. Ahorré 8 bytes cambiando mi salida intermedia de
[l,b]
a[b,-l]
; Esto me permitió pasar el primer resultado directamente como el parámetro de la segunda llamada, además de un pequeño ahorro para detectar si la segunda llamada fue exitosa. Ahorré 2 bytes moviendo la definición deg
en lasome
devolución de llamada, lo que me permite evitar pasar innecesariamente la variable de bucle dos veces. Ahorré 12 bytes al cambiar de mi función auxiliar recursiva a una llamada afilter
(hecho posible por mi interruptor de salida intermedio).fuente
Perl, 69 bytes
Incluye +2 para
-pa
Dar monedas en orden descendente en STDIN. Opcionalmente, puede dejar de lado la
1
moneda.coins.pl
:Acumula el número de monedas utilizadas por el algoritmo de cajero en
@G
cantidades de 1 a dos veces la moneda más grande. Para cada cantidad, comprueba que si esa cantidad se reduce en 1 valor de moneda, el algoritmo de cajero necesita como máximo 1 moneda menos. Si no, este es un contraejemplo (o hubo un contraejemplo anterior). Podría detenerme en el primer contraejemplo, pero eso requiere más bytes. Entonces, la complejidad del tiempo esO(max_coin * coins)
y la complejidad del espacio esO(max_coin)
fuente