Найдите максимально выгодную последовательность обменов по таблице обменных курсов.
В качестве примера рассмотрим валюты A riary (ваша домашняя валюта), B aht, C edi и D enar, где курс от одного к другому (после взимания любой транзакции) задается записью (строка, столбец) в таблица обменного курса ниже:
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
Очевидно, что обменять А на А не очень хорошая идея, так как этот стол с радостью будет брать с вас плату за то, что вы ничего не делаете
Менее очевидно, но с этой таблицей обмен А на любую другую валюту с последующим обменом обратно приводит к убыткам:
via B: 1.719828 × 0.579942 = 0.997400489976
via C: 4.509549 × 0.219978 = 0.992001569922
via D: 0.709929 × 1.39986 = 0.99380120994
Однако обмен A на D, затем D на B, затем B обратно на A приносит прибыль (учитывая достаточный капитал, чтобы не поддаться округлению):
0.709929 × 2.429757 × 0.579942 = 1.0003738278192194
Можно многократно принимать этот «бесплатный обед», пока такая возможность существует.
Но здесь существует еще более заманчивая цепочка, а именно от A до D, затем от D до C, затем от C до B и, наконец, от B до A :
0.709929 × 6.409359 × 0.379962 × 0.579942 = 1.0026612752037345
Детали вызова
Для данной таблицы обменных курсов в любом приемлемом формате, которая фиксирует значение домашней валюты (например, 1- я строка и 1- й столбец всегда являются домашней валютой)
(или с учетом такой таблицы и индекса домашней валюты)
найдите * максимальная арбитражная последовательность обменов, начинающихся и заканчивающихся домашней валютой в качестве индексов в списке валют без повторения использования какой-либо биржи (т. е. биржа Y-> X может следовать за X-> Y, но X-> Y может не следуйте X-> Y).
Если такой выгодной возможности не существует, выведите пустой список или какой-либо другой результат, который нельзя спутать с идентифицированной возможностью.
- например, для приведенного выше примера ( A-> D, D-> C, C-> B, B-> A ):
- используя 0-индексирование можно вернуть
[[0,3],[3,2],[2,1],[1,0]]
или[0,3,2,1,0]
- с помощью 1-индексации можно вернуть
[[1,4],[4,3],[3,2],[2,1]]
или[1,4,3,2,1]
Другие форматы хороши, пока нет никакой двусмысленности.
- Одна вещь, на которую следует обратить внимание, - это то, что наилучшей возможностью является единственная транзакция из дома -> дома (глупый стол). Если вы решили исключить индекс внутренней валюты с обоих концов описанного выше плоского варианта (т. Е. [3,2,1]
Или [4,3,2]
) и пустой список «нет возможности», убедитесь, что home-> home также не является пустым списком.
* Если существует несколько одинаково прибыльных действительных возможностей, верните любой из них, некоторые или все из них.
Алгоритм Беллмана-Форда - один из подходов к этому, но, вероятно, не самый подходящий для гольфа.
Тестовые случаи
Показанные входы находятся в расположении, используемом в примере, и показанные результаты используют 0-индексирование для перечисления индексов к валюте (когда существует возможность, домашняя валюта находится только в конце; ни одна возможность не является пустым списком).
[[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]
Это код-гольф, поэтому выигрывает самое короткое решение в байтах, но соревнование должно быть сделано и внутриязыковым, так что не позволяйте языкам-кодекам отталкивать вас в своем любимом!