Гольф Безкоштовний обід


26

Знайдіть максимально вигідну послідовність обмінів, задану таблицю обмінних курсів.


В якості прикладу розглянемо валюти riary (домашній валюти), Б АГТ, С EDI, і D ЕСПР де швидкість від одного до іншого (після будь-якої ставки угода була стягуються) задається (рядок, стовпець) записи в таблиця обмінних курсів нижче:

                       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

Очевидно, що обмін « А на А» не є чудовою ідеєю, оскільки цей стіл із задоволенням зажадає вас за те, що нічого не робите.

Менш очевидно, але вірно з цією таблицею, обмін втратами A на будь-яку іншу валюту та повторний обмін назад - це збиток:

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]

Це тому найкоротше рішення в байтах виграє, але конкуренція повинна бути також внутрішньомовною, так що не дозволяйте мовам кодового гольфу відкладати подання у вашому улюбленому!

Відповіді:


8

JavaScript (ES6), 122 113 103 байт

Приймає введення як транспоновану матрицю щодо формату, описаного в виклику. Повертає рядок, що описує обмін у (from,to)форматі.

a=>(g=(s,x=b=0,h='')=>a.map((r,y)=>~h.search(k=`(${x},${y})`)||g(s*r[x],y,h+k),x|s<b||(b=s,p=h)))(1)&&p

Перший тестовий випадок: спробуйте в Інтернеті!

Більше тестових випадків: спробуйте в Інтернеті!

Прокоментував

a => (                  // given the exchange rate matrix a[][]
  g = (                 // g = recursive function taking:
    s,                  //   s = current amount of money
    x = b = 0,          //   x = ID of current currency, b = best result so far
    h = ''              //   h = exchange history, as a string
  ) =>                  //  
  a.map((r, y) =>       // for each row at position y in a[]:
    ~h.search(          //   if we can't find in h ...
      k = `(${x},${y})` //     ... the exchange key k from currency x to currency y
    ) ||                //   then:
    g(                  //   do a recursive call to g() with:
      s * r[x],         //     s = new amount obtained by applying the exchange rate
      y,                //     x = y
      h + k             //     h = h + k
    ),                  //   end of recursive call
    x | s < b ||        //   if x is our home currency and s is greater than or equal to b
    (b = s, p = h)      //   then set b to s and set p to h
  )                     // end of map()
)(1)                    // initial call to g() with s = 1
&& p                    // return p

4

Python 2 , 143 125 124 байт

lambda M:g(M)[1]
g=lambda M,s=[],p=1,x=0:max([(p,s)]*-~-x+[g(M,s+[(x,y)],p*M[x][y],y)for y in range(len(M))if(x,y)not in s])

Спробуйте в Інтернеті!

Використовує індексацію на основі 0 (домашня валюта - 0); повертає список кортежів бірж, даючи максимальну виплату.

Підхід грубої сили: з допомогою рекурсії, ми в кінцевому підсумку відвідування кожен некраевого-повторює шлях , починаючи з 0(для nтого кількість валют, це дає максимальну глибину в n^2). Для підмножини цих контурів, що також закінчується на "0", ми максимально виграємо.


1

Haskell, 175 байт

e?l|e`elem`l=0|2>1=1
w[]=[]
w l=[maximum l];0!q=[q]
n!c@(v,i,(h,l))=do{j<-[0..3];c:((n-1)!(v*l!!i!!j*(i,j)?h,j,((i,j):h,l)))}
z l=w$filter(\(v,e,_)->v>1&&e==0)$12!(1,0,([],l))

Спробуйте тут

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.