高尔夫免费午餐


26

在给定汇率表的情况下,找到最大获利的交易所序列。


例如,考虑货币的一个 riary(你的本国货币), AHT,Ç 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

显然,用A交换A并不是一个好主意,因为这张桌子会很乐意向您收取任何费用。

不太明显,但在此表中是正确的,将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

在机会存在的时候,人们可以反复吃这种“免费午餐”。

但是这里存在一个更诱人的链,即AD,然后DC,然后CB,最后是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]

只要没有歧义,其他格式也可以。
-要提防的一件事是,最好的机会是从home-> home(一个愚蠢的办公桌)进行一次交易。如果您决定从上面的flat选项的两端(即[3,2,1][4,3,2])中排除本国货币指数,并为“无机会”创建一个空列表,则请确保home-> home也不为空列表。

*如果碰巧存在多个同等可获利的有效机会,则退还其中任何一个,其中一些或全部。

Bellman-Ford算法是解决此问题的一种方法,但可能不是最适合高尔夫的方法。

测试用例

所显示的输入在示例中使用的安排中,并且所显示的结果使用0索引列出了to-currency-indices(当机会存在时本国货币仅位于尾端;没有机会是空列表)。

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

这是因此以字节为单位的最短解决方案会获胜,但是竞争也应在内部语言中进行,所以不要让代码高尔夫球语言让您推迟使用自己喜欢的语言提交!

Answers:


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

在这里尝试

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.