Encontre uma sequência de trocas maximamente lucrativa, dada uma tabela de taxas de câmbio.
Como exemplo, considere as moedas A riary (sua moeda local), B aht, C edi e D enar em que a taxa de uma para outra (após a cobrança de qualquer taxa de transação) é dada pela entrada (linha, coluna) em a tabela de taxas de câmbio abaixo:
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, trocar A por A não é uma boa ideia, pois esta mesa o cobrará com prazer por não fazer nada.
Menos obviamente, mas é verdade com esta tabela, trocar A por qualquer outra moeda e depois trocar novamente é um causador de perdas:
via B: 1.719828 × 0.579942 = 0.997400489976
via C: 4.509549 × 0.219978 = 0.992001569922
via D: 0.709929 × 1.39986 = 0.99380120994
No entanto, a troca de A para D , de D para B e de B para A gera lucro (dado capital suficiente para não sucumbir ao arredondamento):
0.709929 × 2.429757 × 0.579942 = 1.0003738278192194
Pode-se repetidamente tomar esse "almoço grátis" enquanto a oportunidade existe.
Mas existe uma cadeia ainda mais atraente aqui, A a D , D a C , C a B e, finalmente, B de volta a A :
0.709929 × 6.409359 × 0.379962 × 0.579942 = 1.0026612752037345
Detalhes do Desafio
Dada uma tabela de taxa de câmbio em qualquer formato razoável, que fixa o significado da casa da moeda (por exemplo, 1 st linha e 1 st coluna são sempre os home-moeda)
(ou dado tal tabela e um índice de home-moeda)
encontrar um * sequência máxima de arbitragem de trocas começando e terminando com a moeda local como índices na lista de moedas sem repetir o uso de qualquer troca (ou seja, uma troca Y-> X pode seguir uma X-> Y, mas uma X-> Y não pode siga um X-> Y).
Se não existir essa oportunidade lucrativa, produza uma lista vazia ou algum outro resultado não confundível com uma oportunidade identificada.
- por exemplo, para o exemplo acima ( A-> D, D-> C, C-> B, B-> A ):
- usando a indexação 0, pode-se retornar
[[0,3],[3,2],[2,1],[1,0]]
ou[0,3,2,1,0]
- usando a indexação 1, um pode retornar
[[1,4],[4,3],[3,2],[2,1]]
ou[1,4,3,2,1]
Outros formatos são bons, desde que não haja ambiguidade.
- Uma coisa a observar é que é possível que a melhor oportunidade seja uma única transação de casa-> casa (uma mesa tola). Se você optar por excluir o índice da moeda local das duas extremidades da opção fixa acima ( [3,2,1]
ou seja [4,3,2]
) e uma lista vazia para "sem oportunidade", verifique se a casa-> casa também não é uma lista vazia.
* Se existirem várias oportunidades válidas igualmente lucrativas, retorne qualquer uma delas, algumas delas ou todas.
O algoritmo Bellman-Ford é uma maneira de abordar isso, mas provavelmente não é o mais adequado para o golfe.
Casos de teste
As entradas mostradas estão no arranjo usado no exemplo, e os resultados mostrados usam a indexação 0 para listar os índices de moeda (quando existe uma oportunidade, a moeda local fica apenas no final da trilha; nenhuma oportunidade é uma lista vazia).
[[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 é o código-golfe, por isso vence a solução mais curta em bytes, mas a competição também deve ser feita dentro do idioma; portanto, não deixe que os idiomas de código-golfe o impeçam de enviar o seu favorito!