Golf Ein kostenloses Mittagessen

26

Finden Sie anhand einer Kurstabelle eine maximal rentable Abfolge von Börsen.


Betrachten Sie als Beispiel die Währungen A riary (Ihre Heimatwährung), B aht, C edi und D enar, bei denen der Wechselkurs (nachdem ein Transaktionskurs erhoben wurde) durch den Eintrag in (Zeile, Spalte) angegeben wird die Wechselkurstabelle unten:

                       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

Offensichtlich ist es keine gute Idee , A gegen A zu tauschen, da Sie an diesem Schreibtisch gerne dafür belastet werden, dass Sie nichts tun.

Weniger offensichtlich, aber bei dieser Tabelle stimmt es, wenn A gegen eine andere Währung getauscht und dann wieder zurückgetauscht wird:

via B: 1.719828 × 0.579942 = 0.997400489976
via C: 4.509549 × 0.219978 = 0.992001569922
via D: 0.709929 × 1.39986  = 0.99380120994

Ein Umtausch von A nach D, dann von D nach B und dann von B zurück nach A bringt jedoch Gewinn (vorausgesetzt, dass genügend Kapital vorhanden ist, um der Rundung nicht zu erliegen):

0.709929 × 2.429757 × 0.579942 = 1.0003738278192194

Man könnte dieses "kostenlose Mittagessen" wiederholt einnehmen, solange die Gelegenheit besteht.

Aber hier gibt es eine noch verlockendere Kette, nämlich von A nach D, dann von D nach C, dann von C nach B und schließlich von B nach A :

0.709929 × 6.409359 × 0.379962 × 0.579942 = 1.0026612752037345

Herausforderungsdetails

Wenn eine Wechselkurstabelle in einem angemessenen Format vorliegt, das die Bedeutung der Heimatwährung festlegt (z. B. sind die erste Zeile und die erste Spalte immer die Heimatwährung)
(oder wenn eine solche Tabelle und ein Heimatwährungsindex vorliegen)
, ist ein * zu finden. Maximale Arbitrage-Reihenfolge der Börsen , die mit der Heimatwährung als Index in der Währungsliste beginnen und enden, ohne die Verwendung einer beliebigen Börse zu wiederholen (dh eine Y-> X-Börse kann einer X-> Y-Börse folgen, eine X-> Y-Börse jedoch nicht) folge einem X-> Y).

Wenn keine solche profitable Gelegenheit besteht, geben Sie eine leere Liste oder ein anderes Ergebnis heraus, das nicht mit einer identifizierten Gelegenheit verwechselt werden kann.
- zB für das obige Beispiel ( A-> D, D-> C, C-> B, B-> A ):

  • mit 0-Indexierung kann man [[0,3],[3,2],[2,1],[1,0]]oder zurückgeben[0,3,2,1,0]
  • mit 1-Indexierung kann man [[1,4],[4,3],[3,2],[2,1]]oder zurückgeben[1,4,3,2,1]

Andere Formate sind in Ordnung, solange keine Mehrdeutigkeiten bestehen.
- Eine Sache, auf die Sie achten sollten, ist, dass es für die beste Gelegenheit möglich ist, eine einzelne Transaktion von zu Hause aus zu tätigen (ein dummer Schreibtisch). Wenn Sie sich dafür entscheiden, den Heimatwährungsindex von beiden Enden der obigen Flat-Option (dh [3,2,1]oder [4,3,2]) und eine leere Liste für "keine Chance" auszuschließen, stellen Sie sicher, dass die Heimat-> Heimat nicht auch eine leere Liste ist.

* Wenn mehrere, gleichermaßen profitable, gültige Opportunities vorhanden sind, geben Sie eine davon, einige davon oder alle zurück.

Der Bellman-Ford-Algorithmus ist eine Möglichkeit, dies zu erreichen, aber wahrscheinlich nicht die beste für Golf.

Testfälle

Die angezeigten Eingaben entsprechen der im Beispiel verwendeten Anordnung, und die angezeigten Ergebnisse verwenden die 0-Indizierung, um die Währungsindizes aufzulisten.

[[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]

Dies ist daher gewinnt die kürzeste Lösung in Bytes, aber der Wettbewerb sollte auch in der Sprache stattfinden. Lassen Sie sich also nicht von Code-Golf-Sprachen davon abhalten, Ihre Lieblingslösung einzureichen!

Jonathan Allan
quelle

Antworten:

8

JavaScript (ES6), 122 113 103 Byte

Nimmt die Eingabe als transponierte Matrix in Bezug auf das in der Abfrage beschriebene Format. Gibt eine Zeichenfolge zurück, die den Austausch im (from,to)Format beschreibt.

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

Erster Testfall: Online ausprobieren !

Weitere Testfälle: Probieren Sie es online aus!

Kommentiert

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
Arnauld
quelle
4

Python 2 , 143 125 124 Bytes

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])

Probieren Sie es online!

Verwendet eine 0-basierte Indexierung (0 ist die Heimatwährung); Gibt eine Liste mit Tupeln der Börsen zurück, die die maximale Auszahlung ergeben.

Der Ansatz ist Brute Force: Über die Rekursion besuchen wir am Ende jeden nicht kantenwiederholenden Pfad, der bei 0(für ndie Anzahl der Währungen ergibt dies eine maximale Tiefe von n^2) beginnt . Für die Teilmenge dieser Pfade, die ebenfalls mit '0' endet, maximieren wir die Auszahlung.

Chas Brown
quelle
1

Haskell, 175 Bytes

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))

Probieren Sie es hier aus

Radek
quelle