01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package algs44;
import stdlib.*;
/* ***********************************************************************
 *  Compilation:  javac Arbitrage.java
 *  Execution:    java Arbitrage < input.txt
 *  Dependencies: EdgeWeightedDigraph.java DirectedEdge.java
 *                BellmanFordSP.java
 *  Data file:    http://algs4.cs.princeton.edu/44sp/rates.txt
 *
 *  Arbitrage detection.
 *
 *  % more rates.txt
 *  5
 *  USD 1      0.741  0.657  1.061  1.005
 *  EUR 1.349  1      0.888  1.433  1.366
 *  GBP 1.521  1.126  1      1.614  1.538
 *  CHF 0.942  0.698  0.619  1      0.953
 *  CAD 0.995  0.732  0.650  1.049  1
 *
 *  % java Arbitrage < rates.txt
 *  1000.00000 USD =  741.00000 EUR
 *   741.00000 EUR = 1012.20600 CAD
 *  1012.20600 CAD = 1007.14497 USD
 *
 *************************************************************************/

public class Arbitrage {

  public static void main(String[] args) {

    // V currencies
    int V = StdIn.readInt();
    String[] name = new String[V];

    // create complete network
    EdgeWeightedDigraph G = new EdgeWeightedDigraph(V);
    for (int v = 0; v < V; v++) {
      name[v] = StdIn.readString();
      for (int w = 0; w < V; w++) {
        double rate = StdIn.readDouble();
        DirectedEdge e = new DirectedEdge(v, w, -Math.log(rate));
        G.addEdge(e);
      }
    }

    // find negative cycle
    BellmanFordSP spt = new BellmanFordSP(G, 0);
    if (spt.hasNegativeCycle()) {
      double stake = 1000.0;
      for (DirectedEdge e : spt.negativeCycle()) {
        StdOut.format("%10.5f %s ", stake, name[e.from()]);
        stake *= Math.exp(-e.weight());
        StdOut.format("= %10.5f %s\n", stake, name[e.to()]);
      }
    }
    else {
      StdOut.println("No arbitrage opportunity");
    }
  }

}