Encuentre una secuencia de intercambios máximamente rentable dada una tabla de tipos de cambio.
Como ejemplo, considere las monedas A riary (su moneda local), B aht, C edi y D enar, donde la tasa de una a otra (después de que se haya aplicado cualquier tasa de transacción) viene dada por la entrada (fila, columna) en la tabla de tipo de cambio a continuación:
TO
A B C D
A 0.9999 1.719828 4.509549 0.709929
F B 0.579942 0.9999 2.619738 0.409959
R
O C 0.219978 0.379962 0.9999 0.149985
M
D 1.39986 2.429757 6.409359 0.9999
Obviamente, intercambiar A por A no es una gran idea, ya que este escritorio le cobrará felizmente por no hacer nada.
Menos obvio, pero cierto con esta tabla, el intercambio de A por cualquier otra moneda y luego el intercambio de nuevo es un factor de pérdida:
via B: 1.719828 × 0.579942 = 0.997400489976
via C: 4.509549 × 0.219978 = 0.992001569922
via D: 0.709929 × 1.39986 = 0.99380120994
Sin embargo, intercambiando A por D, luego D por B y luego B de regreso a A genera ganancias (dado el capital suficiente para no sucumbir al redondeo)
0.709929 × 2.429757 × 0.579942 = 1.0003738278192194
Uno podría tomar repetidamente este "almuerzo gratis" mientras exista la oportunidad.
Pero aquí existe una cadena aún más atractiva, a saber, de A a D , de D a C , de C a B y, finalmente, de B a A :
0.709929 × 6.409359 × 0.379962 × 0.579942 = 1.0026612752037345
Detalles del desafío
Dada una tabla de tipo de cambio en cualquier formato razonable que fije el significado de la moneda local (por ejemplo, la 1ª fila y la 1ª columna son siempre la moneda local)
(o dada una tabla y un índice de la moneda local)
encuentre un * secuencia de arbitraje máxima de intercambios que comienzan y terminan con la moneda local como índices en la lista de divisas sin repetir el uso de ningún intercambio (es decir, un intercambio Y-> X puede seguir a uno X-> Y, pero un X-> Y no puede siga una X-> Y).
Si no existe tal oportunidad rentable, proporcione una lista vacía o algún otro resultado que no sea confuso con una oportunidad identificada.
- por ejemplo, para el ejemplo anterior ( A-> D, D-> C, C-> B, B-> A ):
- usando indexación 0, uno podría regresar
[[0,3],[3,2],[2,1],[1,0]]
o[0,3,2,1,0]
- usando 1 indexación, uno podría regresar
[[1,4],[4,3],[3,2],[2,1]]
o[1,4,3,2,1]
Otros formatos están bien siempre que no haya ambigüedad.
- Una cosa a tener en cuenta es que es posible que la mejor oportunidad sea una sola transacción desde casa-> casa (un escritorio tonto). Si decide excluir el índice de moneda local de ambos extremos de la opción plana anterior (es decir, [3,2,1]
o [4,3,2]
) y una lista vacía para "ninguna oportunidad", entonces asegúrese de que home-> home no sea también una lista vacía.
* Si existen múltiples oportunidades válidas igualmente rentables, devuelva alguna de ellas, algunas o todas.
El algoritmo Bellman-Ford es una forma de abordar esto, pero probablemente no sea el más adecuado para el golf.
Casos de prueba
Las entradas que se muestran están en la disposición utilizada en el ejemplo, y los resultados que se muestran usan la indexación 0 para enumerar los índices de moneda (cuando existe una oportunidad, la moneda local está solo en el extremo final; ninguna oportunidad es una lista vacía).
[[0.999900, 1.719828, 4.509549, 0.709929],
[0.579942, 0.999900, 2.619738, 0.409959],
[0.219978, 0.379962, 0.999900, 0.149985],
[1.399860, 2.429757, 6.409359, 0.999900]] -> [3, 2, 1, 0]
[[0.9999, 1.5645, 0.9048, 1.0929],
[0.6382, 0.9999, 0.5790, 0.6998],
[1.1051, 1.7269, 0.9999, 1.2087],
[0.9131, 1.4288, 0.8262, 0.9999]] -> [1, 2, 0]
[[0.9999, 1.4288, 0.8262, 0.9131],
[0.6998, 0.9999, 0.5790, 0.6382],
[1.2087, 1.7269, 0.9999, 1.1051],
[1.0929, 1.5645, 0.9048, 0.9999]] -> [1, 2, 3, 1, 0]
[[1.002662, 1.719828, 4.509549, 0.709929],
[0.579942, 0.999900, 2.619738, 0.409959],
[0.219978, 0.379962, 0.999900, 0.149985],
[1.399860, 2.429757, 6.409359, 0.999900]] -> [3, 2, 1, 0, 0]
[[1.002662, 1.719828, 4.509549, 0.709929],
[0.579942, 1.002604, 2.619738, 0.409959],
[0.219978, 0.379962, 1.003000, 0.149985],
[1.399860, 2.429757, 6.409359, 1.002244]] -> [3, 3, 2, 2, 1, 1, 0, 0]
[[0.9999, 1.4288, 0.8262, 0.9131],
[0.6998, 0.9999, 0.5790, 0.6382],
[1.2087, 1.7269, 1.0001, 1.1051],
[1.0929, 1.4974, 0.9048, 0.9999]] -> [1, 2, 2, 0]
[[0.9999, 1.3262, 0.7262, 0.9131],
[0.6998, 0.9999, 0.5490, 0.6382],
[1.2087, 1.7269, 0.9999, 1.2051],
[1.0929, 1.5645, 0.9048, 0.9999]] -> [3, 2, 3, 1, 0]
[[0.9999, 1.5645, 0.9048, 0.5790],
[0.6382, 0.9999, 0.5790, 0.3585],
[1.1051, 1.7269, 0.9999, 0.6391],
[1.7271, 2.6992, 1.5645, 0.9999]] -> [1, 2, 0] and/or [3, 2, 0]
[[0.9999, 1.2645, 0.7048, 0.3790],
[0.4382, 0.9999, 0.3790, 0.1585],
[1.0001, 1.5269, 1.0001, 0.4391],
[1.5271, 2.4992, 1.3645, 0.9999]] -> []
[[0.9999, 1.2645, 0.7048, 0.3790],
[0.4382, 0.9999, 0.3790, 0.1585],
[0.9999, 1.5269, 1.4190, 0.4391],
[1.5271, 2.4992, 1.3645, 0.9999]] -> [2, 2, 0]
Este es el código de golf, por lo que la solución más corta en bytes gana, pero la competencia también debe hacerse dentro del lenguaje, ¡así que no dejes que los lenguajes de código de golf te impidan enviar tu favorito!