Index: applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/AssignmentProblem.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/AssignmentProblem.java	(revision 28116)
+++ applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/AssignmentProblem.java	(revision 28116)
@@ -0,0 +1,192 @@
+// License: GPL v3 or later courtesy of author Kevin Wayne
+package edu.princeton.cs.algs4;
+
+/*************************************************************************
+ *  Compilation:  javac AssignmentProblem.java
+ *  Execution:    java AssignmentProblem N
+ *  Dependencies: DijkstraSP.java DirectedEdge.java
+ *
+ *  Solve an N-by-N assignment problem in N^3 log N time using the
+ *  successive shortest path algorithm.
+ *
+ *  Remark: could use dense version of Dijsktra's algorithm for
+ *  improved theoretical efficiency of N^3, but it doesn't seem to
+ *  help in practice.
+ *
+ *  Assumes N-by-N cost matrix is nonnegative.
+ *
+ *
+ *********************************************************************/
+
+public class AssignmentProblem {
+    private static final int UNMATCHED = -1;
+
+    private int N;              // number of rows and columns
+    private double[][] weight;  // the N-by-N cost matrix
+    private double[] px;        // px[i] = dual variable for row i
+    private double[] py;        // py[j] = dual variable for col j
+    private int[] xy;           // xy[i] = j means i-j is a match
+    private int[] yx;           // yx[j] = i means i-j is a match
+
+ 
+    public AssignmentProblem(double[][] weight) {
+        N = weight.length;
+        this.weight = new double[N][N];
+        for (int i = 0; i < N; i++)
+            for (int j = 0; j < N; j++)
+                this.weight[i][j] = weight[i][j];
+
+        // dual variables
+        px = new double[N];
+        py = new double[N];
+
+        // initial matching is empty
+        xy = new int[N];
+        yx = new int[N];
+        for (int i = 0; i < N; i++) xy[i] = UNMATCHED;
+        for (int j = 0; j < N; j++) yx[j] = UNMATCHED;
+
+        // add N edges to matching
+        for (int k = 0; k < N; k++) {
+            assert isDualFeasible();
+            assert isComplementarySlack();
+            augment();
+        }
+        assert check();
+    }
+
+    // find shortest augmenting path and upate
+    private void augment() {
+
+        // build residual graph
+        EdgeWeightedDigraph G = new EdgeWeightedDigraph(2*N+2);
+        int s = 2*N, t = 2*N+1;
+        for (int i = 0; i < N; i++) {
+            if (xy[i] == UNMATCHED) G.addEdge(new DirectedEdge(s, i, 0.0));
+        }
+        for (int j = 0; j < N; j++) {
+            if (yx[j] == UNMATCHED) G.addEdge(new DirectedEdge(N+j, t, py[j]));
+        }
+        for (int i = 0; i < N; i++) {
+            for (int j = 0; j < N; j++) {
+                if (xy[i] == j) G.addEdge(new DirectedEdge(N+j, i, 0.0));
+                else            G.addEdge(new DirectedEdge(i, N+j, reduced(i, j)));
+            }
+        }
+
+        // compute shortest path from s to every other vertex
+        DijkstraSP spt = new DijkstraSP(G, s);
+
+        // augment along alternating path
+        for (DirectedEdge e : spt.pathTo(t)) {
+            int i = e.from(), j = e.to() - N;
+            if (i < N) {
+                xy[i] = j;
+                yx[j] = i;
+            }
+        }
+
+        // update dual variables
+        for (int i = 0; i < N; i++) px[i] += spt.distTo(i);
+        for (int j = 0; j < N; j++) py[j] += spt.distTo(N+j);
+    }
+
+    // reduced cost of i-j
+    private double reduced(int i, int j) {
+        return weight[i][j] + px[i] - py[j];
+    }
+
+    // total weight of min weight perfect matching
+    public double weight() {
+        double total = 0.0;
+        for (int i = 0; i < N; i++) {
+            if (xy[i] != UNMATCHED)
+                total += weight[i][xy[i]];
+        }
+        return total;
+    }
+
+    public int sol(int i) {
+        return xy[i];
+    }
+
+    // check that dual variables are feasible
+    private boolean isDualFeasible() {
+        // check that all edges have >= 0 reduced cost
+        for (int i = 0; i < N; i++) {
+            for (int j = 0; j < N; j++) {
+                if (reduced(i, j) < 0) {
+//                    StdOut.println("Dual variables are not feasible");
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    // check that primal and dual variables are complementary slack
+    private boolean isComplementarySlack() {
+
+        // check that all matched edges have 0-reduced cost
+        for (int i = 0; i < N; i++) {
+            if ((xy[i] != UNMATCHED) && (reduced(i, xy[i]) != 0)) {
+//                StdOut.println("Primal and dual variables are not complementary slack");
+                return false;
+            }
+        }
+        return true;
+    }
+
+    // check that primal variables are a perfect matching
+    private boolean isPerfectMatching() {
+
+        // check that xy[] is a perfect matching
+        boolean[] perm = new boolean[N];
+        for (int i = 0; i < N; i++) {
+            if (perm[xy[i]]) {
+//                StdOut.println("Not a perfect matching");
+                return false;
+            }
+            perm[xy[i]] = true;
+        }
+
+        // check that xy[] and yx[] are inverses
+        for (int j = 0; j < N; j++) {
+            if (xy[yx[j]] != j) {
+//                StdOut.println("xy[] and yx[] are not inverses");
+                return false;
+            }
+        }
+        for (int i = 0; i < N; i++) {
+            if (yx[xy[i]] != i) {
+//                StdOut.println("xy[] and yx[] are not inverses");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    // check optimality conditions
+    private boolean check() {
+        return isPerfectMatching() && isDualFeasible() && isComplementarySlack();
+    }
+
+//    public static void main(String[] args) {
+//        In in = new In(args[0]);
+//        int N = in.readInt();
+//        double[][] weight = new double[N][N];
+//        for (int i = 0; i < N; i++) {
+//            for (int j = 0; j < N; j++) {
+//                weight[i][j] = in.readDouble();
+//            }
+//        }
+//
+//        AssignmentProblem assignment = new AssignmentProblem(weight);
+//        StdOut.println("weight = " + assignment.weight());
+//        for (int i = 0; i < N; i++)
+//            StdOut.println(i + "-" + assignment.sol(i) + " " + weight[i][assignment.sol(i)]);
+//    }
+
+}
Index: applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/Bag.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/Bag.java	(revision 28116)
+++ applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/Bag.java	(revision 28116)
@@ -0,0 +1,117 @@
+// License: GPL v3 or later courtesy of author Kevin Wayne
+package edu.princeton.cs.algs4;
+
+/*************************************************************************
+ *  Compilation:  javac Bag.java
+ *  Execution:    java Bag < input.txt
+ *
+ *  A generic bag or multiset, implemented using a linked list.
+ *
+ *************************************************************************/
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ *  The <tt>Bag</tt> class represents a bag (or multiset) of 
+ *  generic items. It supports insertion and iterating over the 
+ *  items in arbitrary order.
+ *  <p>
+ *  The <em>add</em>, <em>isEmpty</em>, and <em>size</em>  operation 
+ *  take constant time. Iteration takes time proportional to the number of items.
+ *  <p>
+ *  For additional documentation, see <a href="http://algs4.cs.princeton.edu/13stacks">Section 1.3</a> of
+ *  <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
+ */
+public class Bag<Item> implements Iterable<Item> {
+    private int N;         // number of elements in bag
+    private Node first;    // beginning of bag
+
+    // helper linked list class
+    private class Node {
+        private Item item;
+        private Node next;
+    }
+
+   /**
+     * Create an empty stack.
+     */
+    public Bag() {
+        first = null;
+        N = 0;
+        assert check();
+    }
+
+   /**
+     * Is the BAG empty?
+     */
+    public boolean isEmpty() {
+        return first == null;
+    }
+
+   /**
+     * Return the number of items in the bag.
+     */
+    public int size() {
+        return N;
+    }
+
+   /**
+     * Add the item to the bag.
+     */
+    public void add(Item item) {
+        Node oldfirst = first;
+        first = new Node();
+        first.item = item;
+        first.next = oldfirst;
+        N++;
+        assert check();
+    }
+
+    // check internal invariants
+    private boolean check() {
+        if (N == 0) {
+            if (first != null) return false;
+        }
+        else if (N == 1) {
+            if (first == null)      return false;
+            if (first.next != null) return false;
+        }
+        else {
+            if (first.next == null) return false;
+        }
+
+        // check internal consistency of instance variable N
+        int numberOfNodes = 0;
+        for (Node x = first; x != null; x = x.next) {
+            numberOfNodes++;
+        }
+        if (numberOfNodes != N) return false;
+
+        return true;
+    } 
+
+
+   /**
+     * Return an iterator that iterates over the items in the bag.
+     */
+    public Iterator<Item> iterator()  {
+        return new ListIterator();  
+    }
+
+    // an iterator, doesn't implement remove() since it's optional
+    private class ListIterator implements Iterator<Item> {
+        private Node current = first;
+
+        public boolean hasNext()  { return current != null;                     }
+        public void remove()      { throw new UnsupportedOperationException();  }
+
+        public Item next() {
+            if (!hasNext()) throw new NoSuchElementException();
+            Item item = current.item;
+            current = current.next; 
+            return item;
+        }
+    }
+
+}
Index: applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/DijkstraSP.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/DijkstraSP.java	(revision 28116)
+++ applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/DijkstraSP.java	(revision 28116)
@@ -0,0 +1,170 @@
+// License: GPL v3 or later courtesy of author Kevin Wayne
+package edu.princeton.cs.algs4;
+
+/*************************************************************************
+ *  Compilation:  javac DijkstraSP.java
+ *  Execution:    java DijkstraSP input.txt s
+ *  Dependencies: EdgeWeightedDigraph.java IndexMinPQ.java Stack.java DirectedEdge.java
+ *  Data files:   http://algs4.cs.princeton.edu/44sp/tinyEWD.txt
+ *                http://algs4.cs.princeton.edu/44sp/mediumEWD.txt
+ *                http://algs4.cs.princeton.edu/44sp/largeEWD.txt
+ *
+ *  Dijkstra's algorithm. Computes the shortest path tree.
+ *  Assumes all weights are nonnegative.
+ *
+ *  % java DijkstraSP tinyEWD.txt 0
+ *  0 to 0 (0.00)  
+ *  0 to 1 (1.05)  0->4  0.38   4->5  0.35   5->1  0.32   
+ *  0 to 2 (0.26)  0->2  0.26   
+ *  0 to 3 (0.99)  0->2  0.26   2->7  0.34   7->3  0.39   
+ *  0 to 4 (0.38)  0->4  0.38   
+ *  0 to 5 (0.73)  0->4  0.38   4->5  0.35   
+ *  0 to 6 (1.51)  0->2  0.26   2->7  0.34   7->3  0.39   3->6  0.52   
+ *  0 to 7 (0.60)  0->2  0.26   2->7  0.34   
+ *
+ *  % java DijkstraSP mediumEWD.txt 0
+ *  0 to 0 (0.00)  
+ *  0 to 1 (0.71)  0->44  0.06   44->93  0.07   ...  107->1  0.07   
+ *  0 to 2 (0.65)  0->44  0.06   44->231  0.10  ...  42->2  0.11   
+ *  0 to 3 (0.46)  0->97  0.08   97->248  0.09  ...  45->3  0.12   
+ *  0 to 4 (0.42)  0->44  0.06   44->93  0.07   ...  77->4  0.11   
+ *  ...
+ *
+ *************************************************************************/
+
+public class DijkstraSP {
+    private double[] distTo;          // distTo[v] = distance  of shortest s->v path
+    private DirectedEdge[] edgeTo;    // edgeTo[v] = last edge on shortest s->v path
+    private IndexMinPQ<Double> pq;    // priority queue of vertices
+
+    public DijkstraSP(EdgeWeightedDigraph G, int s) {
+        distTo = new double[G.V()];
+        edgeTo = new DirectedEdge[G.V()];
+        for (int v = 0; v < G.V(); v++)
+            distTo[v] = Double.POSITIVE_INFINITY;
+        distTo[s] = 0.0;
+
+        // relax vertices in order of distance from s
+        pq = new IndexMinPQ<Double>(G.V());
+        pq.insert(s, distTo[s]);
+        while (!pq.isEmpty()) {
+            int v = pq.delMin();
+            for (DirectedEdge e : G.adj(v))
+                relax(e);
+        }
+
+        // check optimality conditions
+        assert check(G, s);
+    }
+
+    // relax edge e and update pq if changed
+    private void relax(DirectedEdge e) {
+        int v = e.from(), w = e.to();
+        if (distTo[w] > distTo[v] + e.weight()) {
+            distTo[w] = distTo[v] + e.weight();
+            edgeTo[w] = e;
+            if (pq.contains(w)) pq.change(w, distTo[w]);
+            else                pq.insert(w, distTo[w]);
+        }
+    }
+
+    // length of shortest path from s to v
+    public double distTo(int v) {
+        return distTo[v];
+    }
+
+    // is there a path from s to v?
+    public boolean hasPathTo(int v) {
+        return distTo[v] < Double.POSITIVE_INFINITY;
+    }
+
+    // shortest path from s to v as an Iterable, null if no such path
+    public Iterable<DirectedEdge> pathTo(int v) {
+        if (!hasPathTo(v)) return null;
+        Stack<DirectedEdge> path = new Stack<DirectedEdge>();
+        for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) {
+            path.push(e);
+        }
+        return path;
+    }
+
+
+    // check optimality conditions:
+    // (i) for all edges e:            distTo[e.to()] <= distTo[e.from()] + e.weight()
+    // (ii) for all edge e on the SPT: distTo[e.to()] == distTo[e.from()] + e.weight()
+    private boolean check(EdgeWeightedDigraph G, int s) {
+
+        // check that edge weights are nonnegative
+        for (DirectedEdge e : G.edges()) {
+            if (e.weight() < 0) {
+                System.err.println("negative edge weight detected");
+                return false;
+            }
+        }
+
+        // check that distTo[v] and edgeTo[v] are consistent
+        if (distTo[s] != 0.0 || edgeTo[s] != null) {
+            System.err.println("distTo[s] and edgeTo[s] inconsistent");
+            return false;
+        }
+        for (int v = 0; v < G.V(); v++) {
+            if (v == s) continue;
+            if (edgeTo[v] == null && distTo[v] != Double.POSITIVE_INFINITY) {
+                System.err.println("distTo[] and edgeTo[] inconsistent");
+                return false;
+            }
+        }
+
+        // check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight()
+        for (int v = 0; v < G.V(); v++) {
+            for (DirectedEdge e : G.adj(v)) {
+                int w = e.to();
+                if (distTo[v] + e.weight() < distTo[w]) {
+                    System.err.println("edge " + e + " not relaxed");
+                    return false;
+                }
+            }
+        }
+
+        // check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight()
+        for (int w = 0; w < G.V(); w++) {
+            if (edgeTo[w] == null) continue;
+            DirectedEdge e = edgeTo[w];
+            int v = e.from();
+            if (w != e.to()) return false;
+            if (distTo[v] + e.weight() != distTo[w]) {
+                System.err.println("edge " + e + " on shortest path not tight");
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+//    public static void main(String[] args) {
+//        In in = new In(args[0]);
+//        EdgeWeightedDigraph G = new EdgeWeightedDigraph(in);
+//        int s = Integer.parseInt(args[1]);
+//
+//        // compute shortest paths
+//        DijkstraSP sp = new DijkstraSP(G, s);
+//
+//
+//        // print shortest path
+//        for (int t = 0; t < G.V(); t++) {
+//            if (sp.hasPathTo(t)) {
+//                StdOut.printf("%d to %d (%.2f)  ", s, t, sp.distTo(t));
+//                if (sp.hasPathTo(t)) {
+//                    for (DirectedEdge e : sp.pathTo(t)) {
+//                        StdOut.print(e + "   ");
+//                    }
+//                }
+//                StdOut.println();
+//            }
+//            else {
+//                StdOut.printf("%d to %d         no path\n", s, t);
+//            }
+//        }
+//    }
+
+}
Index: applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/DirectedEdge.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/DirectedEdge.java	(revision 28116)
+++ applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/DirectedEdge.java	(revision 28116)
@@ -0,0 +1,66 @@
+// License: GPL v3 or later courtesy of author Kevin Wayne
+package edu.princeton.cs.algs4;
+
+/*************************************************************************
+ *  Compilation:  javac DirectedEdge.java
+ *  Execution:    java DirectedEdge
+ *
+ *  Immutable weighted directed edge.
+ *
+ *************************************************************************/
+
+/**
+ *  The <tt>DirectedEdge</tt> class represents a weighted edge in an directed graph.
+ *  <p>
+ *  For additional documentation, see <a href="http://algs4.cs.princeton.edu/44sp">Section 4.4</a> of
+ *  <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
+ */
+
+public class DirectedEdge { 
+    private final int v;
+    private final int w;
+    private final double weight;
+
+   /**
+     * Create a directed edge from v to w with given weight.
+     */
+    public DirectedEdge(int v, int w, double weight) {
+        this.v = v;
+        this.w = w;
+        this.weight = weight;
+    }
+
+   /**
+     * Return the vertex where this edge begins.
+     */
+    public int from() {
+        return v;
+    }
+
+   /**
+     * Return the vertex where this edge ends.
+     */
+    public int to() {
+        return w;
+    }
+
+   /**
+     * Return the weight of this edge.
+     */
+    public double weight() { return weight; }
+
+   /**
+     * Return a string representation of this edge.
+     */
+    public String toString() {
+        return v + "->" + w + " " + String.format("%5.2f", weight);
+    }
+
+   /**
+     * Test client.
+     */
+//    public static void main(String[] args) {
+//        DirectedEdge e = new DirectedEdge(12, 23, 3.14);
+//        StdOut.println(e);
+//    }
+}
Index: applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/EdgeWeightedDigraph.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/EdgeWeightedDigraph.java	(revision 28116)
+++ applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/EdgeWeightedDigraph.java	(revision 28116)
@@ -0,0 +1,174 @@
+// License: GPL v3 or later courtesy of author Kevin Wayne
+package edu.princeton.cs.algs4;
+
+/*************************************************************************
+ *  Compilation:  javac EdgeWeightedDigraph.java
+ *  Execution:    java EdgeWeightedDigraph V E
+ *  Dependencies: Bag.java DirectedEdge.java
+ *
+ *  An edge-weighted digraph, implemented using adjacency lists.
+ *
+ *************************************************************************/
+
+/**
+ *  The <tt>EdgeWeightedDigraph</tt> class represents an directed graph of vertices
+ *  named 0 through V-1, where each edge has a real-valued weight.
+ *  It supports the following operations: add an edge to the graph,
+ *  iterate over all of edges leaving a vertex.
+ *  Parallel edges and self-loops are permitted.
+ *  <p>
+ *  For additional documentation, see <a href="http://algs4.cs.princeton.edu/44sp">Section 4.4</a> of
+ *  <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
+ */
+
+
+
+public class EdgeWeightedDigraph {
+    private final int V;
+    private int E;
+    private Bag<DirectedEdge>[] adj;
+    
+    /**
+     * Create an empty edge-weighted digraph with V vertices.
+     */
+    public EdgeWeightedDigraph(int V) {
+        if (V < 0) throw new RuntimeException("Number of vertices must be nonnegative");
+        this.V = V;
+        this.E = 0;
+        adj = (Bag<DirectedEdge>[]) new Bag[V];
+        for (int v = 0; v < V; v++)
+            adj[v] = new Bag<DirectedEdge>();
+    }
+
+   /**
+     * Create a edge-weighted digraph with V vertices and E edges.
+     */
+    public EdgeWeightedDigraph(int V, int E) {
+        this(V);
+        if (E < 0) throw new RuntimeException("Number of edges must be nonnegative");
+        for (int i = 0; i < E; i++) {
+            int v = (int) (Math.random() * V);
+            int w = (int) (Math.random() * V);
+            double weight = Math.round(100 * Math.random()) / 100.0;
+            DirectedEdge e = new DirectedEdge(v, w, weight);
+            addEdge(e);
+        }
+    }
+
+    /**
+     * Create an edge-weighted digraph from input stream.
+     */
+//    public EdgeWeightedDigraph(In in) {
+//        this(in.readInt());
+//        int E = in.readInt();
+//        for (int i = 0; i < E; i++) {
+//            int v = in.readInt();
+//            int w = in.readInt();
+//            double weight = in.readDouble();
+//            addEdge(new DirectedEdge(v, w, weight));
+//        }
+//    }
+
+   /**
+     * Copy constructor.
+     */
+    public EdgeWeightedDigraph(EdgeWeightedDigraph G) {
+        this(G.V());
+        this.E = G.E();
+        for (int v = 0; v < G.V(); v++) {
+            // reverse so that adjacency list is in same order as original
+            Stack<DirectedEdge> reverse = new Stack<DirectedEdge>();
+            for (DirectedEdge e : G.adj[v]) {
+                reverse.push(e);
+            }
+            for (DirectedEdge e : reverse) {
+                adj[v].add(e);
+            }
+        }
+    }
+
+   /**
+     * Return the number of vertices in this digraph.
+     */
+    public int V() {
+        return V;
+    }
+
+   /**
+     * Return the number of edges in this digraph.
+     */
+    public int E() {
+        return E;
+    }
+
+
+   /**
+     * Add the edge e to this digraph.
+     */
+    public void addEdge(DirectedEdge e) {
+        int v = e.from();
+        adj[v].add(e);
+        E++;
+    }
+
+
+   /**
+     * Return the edges leaving vertex v as an Iterable.
+     * To iterate over the edges leaving vertex v, use foreach notation:
+     * <tt>for (DirectedEdge e : graph.adj(v))</tt>.
+     */
+    public Iterable<DirectedEdge> adj(int v) {
+        return adj[v];
+    }
+
+   /**
+     * Return all edges in this graph as an Iterable.
+     * To iterate over the edges, use foreach notation:
+     * <tt>for (DirectedEdge e : graph.edges())</tt>.
+     */
+    public Iterable<DirectedEdge> edges() {
+        Bag<DirectedEdge> list = new Bag<DirectedEdge>();
+        for (int v = 0; v < V; v++) {
+            for (DirectedEdge e : adj(v)) {
+                list.add(e);
+            }
+        }
+        return list;
+    } 
+
+   /**
+     * Return number of edges leaving v.
+     */
+    public int outdegree(int v) {
+        return adj[v].size();
+    }
+
+
+
+   /**
+     * Return a string representation of this graph.
+     */
+    public String toString() {
+        String NEWLINE = System.getProperty("line.separator");
+        StringBuilder s = new StringBuilder();
+        s.append(V + " " + E + NEWLINE);
+        for (int v = 0; v < V; v++) {
+            s.append(v + ": ");
+            for (DirectedEdge e : adj[v]) {
+                s.append(e + "  ");
+            }
+            s.append(NEWLINE);
+        }
+        return s.toString();
+    }
+
+    /**
+     * Test client.
+     */
+//    public static void main(String[] args) {
+//        In in = new In(args[0]);
+//        EdgeWeightedDigraph G = new EdgeWeightedDigraph(in);
+//        StdOut.println(G);
+//    }
+
+}
Index: applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/IndexMinPQ.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/IndexMinPQ.java	(revision 28116)
+++ applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/IndexMinPQ.java	(revision 28116)
@@ -0,0 +1,220 @@
+// License: GPL v3 or later courtesy of author Kevin Wayne
+package edu.princeton.cs.algs4;
+
+/*************************************************************************
+ *  Compilation:  javac IndexMinPQ.java
+ *  Execution:    java IndexMinPQ
+ *
+ *  Indexed PQ implementation using a binary heap.
+ *
+ *********************************************************************/
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class IndexMinPQ<Key extends Comparable<Key>> implements Iterable<Integer> {
+    private int N;           // number of elements on PQ
+    private int[] pq;        // binary heap using 1-based indexing
+    private int[] qp;        // inverse of pq - qp[pq[i]] = pq[qp[i]] = i
+    private Key[] keys;      // keys[i] = priority of i
+
+    public IndexMinPQ(int NMAX) {
+        keys = (Key[]) new Comparable[NMAX + 1];    // make this of length NMAX??
+        pq   = new int[NMAX + 1];
+        qp   = new int[NMAX + 1];                   // make this of length NMAX??
+        for (int i = 0; i <= NMAX; i++) qp[i] = -1;
+    }
+
+    // is the priority queue empty?
+    public boolean isEmpty() { return N == 0; }
+
+    // is k an index on the priority queue?
+    public boolean contains(int k) {
+        return qp[k] != -1;
+    }
+
+    // number of keys in the priority queue
+    public int size() {
+        return N;
+    }
+
+    // associate key with index k
+    public void insert(int k, Key key) {
+        if (contains(k)) throw new NoSuchElementException("item is already in pq");
+        N++;
+        qp[k] = N;
+        pq[N] = k;
+        keys[k] = key;
+        swim(N);
+    }
+
+    // return the index associated with a minimal key
+    public int minIndex() { 
+        if (N == 0) throw new NoSuchElementException("Priority queue underflow");
+        return pq[1];        
+    }
+
+    // return a minimal key
+    public Key minKey() { 
+        if (N == 0) throw new NoSuchElementException("Priority queue underflow");
+        return keys[pq[1]];        
+    }
+
+    // delete a minimal key and returns its associated index
+    public int delMin() { 
+        if (N == 0) throw new NoSuchElementException("Priority queue underflow");
+        int min = pq[1];        
+        exch(1, N--); 
+        sink(1);
+        qp[min] = -1;            // delete
+        keys[pq[N+1]] = null;    // to help with garbage collection
+        pq[N+1] = -1;            // not needed
+        return min; 
+    }
+
+    // return key associated with index k
+    public Key keyOf(int k) {
+        if (!contains(k)) throw new NoSuchElementException("item is not in pq");
+        else return keys[k];
+    }
+
+    // change the key associated with index k
+    public void change(int k, Key key) {
+        changeKey(k, key);
+    }
+
+    // change the key associated with index k
+    public void changeKey(int k, Key key) {
+        if (!contains(k)) throw new NoSuchElementException("item is not in pq");
+        keys[k] = key;
+        swim(qp[k]);
+        sink(qp[k]);
+    }
+
+    // decrease the key associated with index k
+    public void decreaseKey(int k, Key key) {
+        if (!contains(k)) throw new NoSuchElementException("item is not in pq");
+        if (keys[k].compareTo(key) <= 0) throw new RuntimeException("illegal decrease");
+        keys[k] = key;
+        swim(qp[k]);
+    }
+
+    // increase the key associated with index k
+    public void increaseKey(int k, Key key) {
+        if (!contains(k)) throw new NoSuchElementException("item is not in pq");
+        if (keys[k].compareTo(key) >= 0) throw new RuntimeException("illegal decrease");
+        keys[k] = key;
+        sink(qp[k]);
+    }
+
+    // delete the key associated with index k
+    public void delete(int k) {
+        if (!contains(k)) throw new NoSuchElementException("item is not in pq");
+        int index = qp[k];
+        exch(index, N--);
+        swim(index);
+        sink(index);
+        keys[k] = null;
+        qp[k] = -1;
+    }
+
+
+   /**************************************************************
+    * General helper functions
+    **************************************************************/
+    private boolean greater(int i, int j) {
+        return keys[pq[i]].compareTo(keys[pq[j]]) > 0;
+    }
+
+    private void exch(int i, int j) {
+        int swap = pq[i]; pq[i] = pq[j]; pq[j] = swap;
+        qp[pq[i]] = i; qp[pq[j]] = j;
+    }
+
+
+   /**************************************************************
+    * Heap helper functions
+    **************************************************************/
+    private void swim(int k)  {
+        while (k > 1 && greater(k/2, k)) {
+            exch(k, k/2);
+            k = k/2;
+        }
+    }
+
+    private void sink(int k) {
+        while (2*k <= N) {
+            int j = 2*k;
+            if (j < N && greater(j, j+1)) j++;
+            if (!greater(k, j)) break;
+            exch(k, j);
+            k = j;
+        }
+    }
+
+
+   /***********************************************************************
+    * Iterators
+    **********************************************************************/
+
+   /**
+     * Return an iterator that iterates over all of the elements on the
+     * priority queue in ascending order.
+     * <p>
+     * The iterator doesn't implement <tt>remove()</tt> since it's optional.
+     */
+    public Iterator<Integer> iterator() { return new HeapIterator(); }
+
+    private class HeapIterator implements Iterator<Integer> {
+        // create a new pq
+        private IndexMinPQ<Key> copy;
+
+        // add all elements to copy of heap
+        // takes linear time since already in heap order so no keys move
+        public HeapIterator() {
+            copy = new IndexMinPQ<Key>(pq.length - 1);
+            for (int i = 1; i <= N; i++)
+                copy.insert(pq[i], keys[pq[i]]);
+        }
+
+        public boolean hasNext()  { return !copy.isEmpty();                     }
+        public void remove()      { throw new UnsupportedOperationException();  }
+
+        public Integer next() {
+            if (!hasNext()) throw new NoSuchElementException();
+            return copy.delMin();
+        }
+    }
+
+
+//    public static void main(String[] args) {
+//        // insert a bunch of strings
+//        String[] strings = { "it", "was", "the", "best", "of", "times", "it", "was", "the", "worst" };
+//
+//        IndexMinPQ<String> pq = new IndexMinPQ<String>(strings.length);
+//        for (int i = 0; i < strings.length; i++) {
+//            pq.insert(i, strings[i]);
+//        }
+//
+//        // delete and print each key
+//        while (!pq.isEmpty()) {
+//            int i = pq.delMin();
+//            StdOut.println(i + " " + strings[i]);
+//        }
+//        StdOut.println();
+//
+//        // reinsert the same strings
+//        for (int i = 0; i < strings.length; i++) {
+//            pq.insert(i, strings[i]);
+//        }
+//
+//        // print each key using the iterator
+//        for (int i : pq) {
+//            StdOut.println(i + " " + strings[i]);
+//        }
+//        while (!pq.isEmpty()) {
+//            pq.delMin();
+//        }
+//
+//    }
+}
Index: applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/Stack.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/Stack.java	(revision 28116)
+++ applications/editors/josm/plugins/utilsplugin2/src/edu/princeton/cs/algs4/Stack.java	(revision 28116)
@@ -0,0 +1,170 @@
+// License: GPL v3 or later courtesy of author Kevin Wayne
+package edu.princeton.cs.algs4;
+
+/*************************************************************************
+ *  Compilation:  javac Stack.java
+ *  Execution:    java Stack < input.txt
+ *
+ *  A generic stack, implemented using a linked list. Each stack
+ *  element is of type Item.
+ *  
+ *  % more tobe.txt 
+ *  to be or not to - be - - that - - - is
+ *
+ *  % java Stack < tobe.txt
+ *  to be not that or be (2 left on stack)
+ *
+ *************************************************************************/
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+
+/**
+ *  The <tt>Stack</tt> class represents a last-in-first-out (LIFO) stack of generic items.
+ *  It supports the usual <em>push</em> and <em>pop</em> operations, along with methods
+ *  for peeking at the top item, testing if the stack is empty, and iterating through
+ *  the items in LIFO order.
+ *  <p>
+ *  All stack operations except iteration are constant time.
+ *  <p>
+ *  For additional documentation, see <a href="/algs4/13stacks">Section 1.3</a> of
+ *  <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
+ */
+public class Stack<Item> implements Iterable<Item> {
+    private int N;          // size of the stack
+    private Node first;     // top of stack
+
+    // helper linked list class
+    private class Node {
+        private Item item;
+        private Node next;
+    }
+
+   /**
+     * Create an empty stack.
+     */
+    public Stack() {
+        first = null;
+        N = 0;
+        assert check();
+    }
+
+   /**
+     * Is the stack empty?
+     */
+    public boolean isEmpty() {
+        return first == null;
+    }
+
+   /**
+     * Return the number of items in the stack.
+     */
+    public int size() {
+        return N;
+    }
+
+   /**
+     * Add the item to the stack.
+     */
+    public void push(Item item) {
+        Node oldfirst = first;
+        first = new Node();
+        first.item = item;
+        first.next = oldfirst;
+        N++;
+        assert check();
+    }
+
+   /**
+     * Delete and return the item most recently added to the stack.
+     * Throw an exception if no such item exists because the stack is empty.
+     */
+    public Item pop() {
+        if (isEmpty()) throw new RuntimeException("Stack underflow");
+        Item item = first.item;        // save item to return
+        first = first.next;            // delete first node
+        N--;
+        assert check();
+        return item;                   // return the saved item
+    }
+
+
+   /**
+     * Return the item most recently added to the stack.
+     * Throw an exception if no such item exists because the stack is empty.
+     */
+    public Item peek() {
+        if (isEmpty()) throw new RuntimeException("Stack underflow");
+        return first.item;
+    }
+
+   /**
+     * Return string representation.
+     */
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        for (Item item : this)
+            s.append(item + " ");
+        return s.toString();
+    }
+       
+
+    // check internal invariants
+    private boolean check() {
+        if (N == 0) {
+            if (first != null) return false;
+        }
+        else if (N == 1) {
+            if (first == null)      return false;
+            if (first.next != null) return false;
+        }
+        else {
+            if (first.next == null) return false;
+        }
+
+        // check internal consistency of instance variable N
+        int numberOfNodes = 0;
+        for (Node x = first; x != null; x = x.next) {
+            numberOfNodes++;
+        }
+        if (numberOfNodes != N) return false;
+
+        return true;
+    } 
+
+
+   /**
+     * Return an iterator to the stack that iterates through the items in LIFO order.
+     */
+    public Iterator<Item> iterator()  { return new ListIterator();  }
+
+    // an iterator, doesn't implement remove() since it's optional
+    private class ListIterator implements Iterator<Item> {
+        private Node current = first;
+        public boolean hasNext()  { return current != null;                     }
+        public void remove()      { throw new UnsupportedOperationException();  }
+
+        public Item next() {
+            if (!hasNext()) throw new NoSuchElementException();
+            Item item = current.item;
+            current = current.next; 
+            return item;
+        }
+    }
+
+
+   /**
+     * A test client.
+     */
+//    public static void main(String[] args) {
+//        Stack<String> s = new Stack<String>();
+//        while (!StdIn.isEmpty()) {
+//            String item = StdIn.readString();
+//            if (!item.equals("-")) s.push(item);
+//            else if (!s.isEmpty()) StdOut.print(s.pop() + " ");
+//        }
+//        StdOut.println("(" + s.size() + " left on stack)");
+//    }
+}
+
Index: applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/replacegeometry/HungarianAlgorithm.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/replacegeometry/HungarianAlgorithm.java	(revision 28045)
+++ 	(revision )
@@ -1,605 +1,0 @@
-/*
- * Created on Apr 25, 2005
- * 
- * Munkres-Kuhn (Hungarian) Algorithm Clean Version: 0.11
- * 
- * Konstantinos A. Nedas                     
- * Department of Spatial Information Science & Engineering
- * University of Maine, Orono, ME 04469-5711, USA
- * kostas@spatial.maine.edu
- * http://www.spatial.maine.edu/~kostas       
- *
- * This Java class implements the Hungarian algorithm [a.k.a Munkres' algorithm,
- * a.k.a. Kuhn algorithm, a.k.a. Assignment problem, a.k.a. Marriage problem,
- * a.k.a. Maximum Weighted Maximum Cardinality Bipartite Matching].
- *
- * [It can be used as a method call from within any main (or other function).]
- * It takes 2 arguments:
- * a. A 2-D array (could be rectangular or square).
- * b. A string ("min" or "max") specifying whether you want the min or max assignment.
- * [It returns an assignment matrix[array.length][2] that contains the row and col of
- * the elements (in the original inputted array) that make up the optimum assignment.]
- *  
- * [This version contains only scarce comments. If you want to understand the 
- * inner workings of the algorithm, get the tutorial version of the algorithm
- * from the same website you got this one (http://www.spatial.maine.edu/~kostas/dev/soft/munkres.htm)]
- * 
- * Any comments, corrections, or additions would be much appreciated. 
- * Credit due to professor Bob Pilgrim for providing an online copy of the
- * pseudocode for this algorithm (http://216.249.163.93/bob.pilgrim/445/munkres.html)
- * 
- * Feel free to redistribute this source code, as long as this header--with
- * the exception of sections in brackets--remains as part of the file.
- * 
- * Requirements: JDK 1.5.0_01 or better.
- * [Created in Eclipse 3.1M6 (www.eclipse.org).]
- * 
- */
-
-package org.openstreetmap.josm.plugins.utilsplugin2.replacegeometry;
-
-import static java.lang.Math.*;
-import java.util.*;
-
-public class HungarianAlgorithm {
-
-	//********************************//
-	//METHODS FOR CONSOLE INPUT-OUTPUT//
-	//********************************//
-	
-	public static int readInput(String prompt)	//Reads input,returns double.
-	{
-		Scanner in = new Scanner(System.in);
-		System.out.print(prompt);
-		int input = in.nextInt();
-		return input;
-	}
-	public static void printTime(double time)	//Formats time output.
-	{
-		String timeElapsed = "";
-		int days = (int)floor(time)/(24 * 3600);
-		int hours = (int)floor(time%(24*3600))/(3600);
-		int minutes = (int)floor((time%3600)/60);
-		int seconds = (int)round(time%60);
-		
-		if (days > 0)
-			timeElapsed = Integer.toString(days) + "d:";
-		if (hours > 0)
-			timeElapsed = timeElapsed + Integer.toString(hours) + "h:";
-		if (minutes > 0)
-			timeElapsed = timeElapsed + Integer.toString(minutes) + "m:";
-		
-		timeElapsed = timeElapsed + Integer.toString(seconds) + "s";
-		System.out.print("\nTotal time required: " + timeElapsed + "\n\n");
-	}
-	
-	//*******************************************//
-	//METHODS THAT PERFORM ARRAY-PROCESSING TASKS//
-	//*******************************************//
-	
-	public static void generateRandomArray	//Generates random 2-D array.
-	(double[][] array, String randomMethod)	
-	{
-		Random generator = new Random();
-		for (int i=0; i<array.length; i++)
-		{
-			for (int j=0; j<array[i].length; j++)
-			{
-				if (randomMethod.equals("random"))
-					{array[i][j] = generator.nextDouble();}
-				if (randomMethod.equals("gaussian"))
-				{
-						array[i][j] = generator.nextGaussian()/4;		//range length to 1.
-						if (array[i][j] > 0.5) {array[i][j] = 0.5;}		//eliminate outliers.
-						if (array[i][j] < -0.5) {array[i][j] = -0.5;}	//eliminate outliers.
-						array[i][j] = array[i][j] + 0.5;				//make elements positive.
-				}
-			}
-		}			
-	}
-	public static double findLargest		//Finds the largest element in a positive array.
-	(double[][] array)
-	//works for arrays where all values are >= 0.
-	{
-		double largest = 0;
-		for (int i=0; i<array.length; i++)
-		{
-			for (int j=0; j<array[i].length; j++)
-			{
-				if (array[i][j] > largest)
-				{
-					largest = array[i][j];
-				}
-			}
-		}
-			
-		return largest;
-	}
-	public static double[][] transpose		//Transposes a double[][] array.
-	(double[][] array)	
-	{
-		double[][] transposedArray = new double[array[0].length][array.length];
-		for (int i=0; i<transposedArray.length; i++)
-		{
-			for (int j=0; j<transposedArray[i].length; j++)
-			{transposedArray[i][j] = array[j][i];}
-		}
-		return transposedArray;
-	}
-	public static double[][] copyOf			//Copies all elements of an array to a new array.
-	(double[][] original)	
-	{
-		double[][] copy = new double[original.length][original[0].length];
-		for (int i=0; i<original.length; i++)
-		{
-			//Need to do it this way, otherwise it copies only memory location
-			System.arraycopy(original[i], 0, copy[i], 0, original[i].length);
-		}
-		
-		return copy;
-	}
-	
-	//**********************************//
-	//METHODS OF THE HUNGARIAN ALGORITHM//
-	//**********************************//
-	
-	public static int[][] hgAlgorithm (double[][] array, String sumType)
-	{
-		double[][] cost = copyOf(array);	//Create the cost matrix
-		
-		if (sumType.equalsIgnoreCase("max"))	//Then array is weight array. Must change to cost.
-		{
-			double maxWeight = findLargest(cost);
-			for (int i=0; i<cost.length; i++)		//Generate cost by subtracting.
-			{
-				for (int j=0; j<cost[i].length; j++)
-				{
-					cost [i][j] = (maxWeight - cost [i][j]);
-				}
-			}
-		}
-		double maxCost = findLargest(cost);		//Find largest cost matrix element (needed for step 6).
-		
-		int[][] mask = new int[cost.length][cost[0].length];	//The mask array.
-		int[] rowCover = new int[cost.length];					//The row covering vector.
-		int[] colCover = new int[cost[0].length];				//The column covering vector.
-		int[] zero_RC = new int[2];								//Position of last zero from Step 4.
-		int step = 1;											
-		boolean done = false;
-		while (done == false)	//main execution loop
-		{ 
-			switch (step)
-		    {
-				case 1:
-					step = hg_step1(step, cost);     
-		    	    break;
-		    	case 2:
-		    	    step = hg_step2(step, cost, mask, rowCover, colCover);
-					break;
-		    	case 3:
-		    	    step = hg_step3(step, mask, colCover);
-					break;
-		    	case 4:
-		    	    step = hg_step4(step, cost, mask, rowCover, colCover, zero_RC);
-					break;
-		    	case 5:
-					step = hg_step5(step, mask, rowCover, colCover, zero_RC);
-					break;
-		    	case 6:
-		    	   	step = hg_step6(step, cost, rowCover, colCover, maxCost);
-					break;
-		  	    case 7:
-		    	    done=true;
-		    	    break;
-		    }
-		}//end while
-		
-		int[][] assignment = new int[array.length][2];	//Create the returned array.
-		for (int i=0; i<mask.length; i++)
-		{
-			for (int j=0; j<mask[i].length; j++)
-			{
-				if (mask[i][j] == 1)
-				{
-					assignment[i][0] = i;
-					assignment[i][1] = j;
-				}
-			}
-		}
-		
-		//If you want to return the min or max sum, in your own main method
-		//instead of the assignment array, then use the following code:
-		/*
-		double sum = 0; 
-		for (int i=0; i<assignment.length; i++)
-		{
-			sum = sum + array[assignment[i][0]][assignment[i][1]];
-		}
-		return sum;
-		*/
-		//Of course you must also change the header of the method to:
-		//public static double hgAlgorithm (double[][] array, String sumType)
-		
-		return assignment;
-	}
-	public static int hg_step1(int step, double[][] cost)
-	{
-		//What STEP 1 does:
-		//For each row of the cost matrix, find the smallest element
-		//and subtract it from from every other element in its row. 
-	    
-	   	double minval;
-	   	
-		for (int i=0; i<cost.length; i++)	
-	   	{									
-	   	    minval=cost[i][0];
-	   	    for (int j=0; j<cost[i].length; j++)	//1st inner loop finds min val in row.
-	   	    {
-	   	        if (minval>cost[i][j])
-	   	        {
-	   	            minval=cost[i][j];
-	   	        }
-			}
-			for (int j=0; j<cost[i].length; j++)	//2nd inner loop subtracts it.
-	   	    {
-	   	        cost[i][j]=cost[i][j]-minval;
-	   	    }
-		}
-	   			    
-		step=2;
-		return step;
-	}
-	public static int hg_step2(int step, double[][] cost, int[][] mask, int[]rowCover, int[] colCover)
-	{
-		//What STEP 2 does:
-		//Marks uncovered zeros as starred and covers their row and column.
-		
-		for (int i=0; i<cost.length; i++)
-	    {
-	        for (int j=0; j<cost[i].length; j++)
-	        {
-	            if ((cost[i][j]==0) && (colCover[j]==0) && (rowCover[i]==0))
-	            {
-	                mask[i][j]=1;
-					colCover[j]=1;
-	                rowCover[i]=1;
-				}
-	        }
-	    }
-							
-		clearCovers(rowCover, colCover);	//Reset cover vectors.
-			    
-		step=3;
-		return step;
-	}
-	public static int hg_step3(int step, int[][] mask, int[] colCover)
-	{
-		//What STEP 3 does:
-		//Cover columns of starred zeros. Check if all columns are covered.
-		
-		for (int i=0; i<mask.length; i++)	//Cover columns of starred zeros.
-	    {
-	        for (int j=0; j<mask[i].length; j++)
-	        {
-	            if (mask[i][j] == 1)
-	            {
-	                colCover[j]=1;
-				}
-	        }
-	    }
-	    
-		int count=0;						
-		for (int j=0; j<colCover.length; j++)	//Check if all columns are covered.
-	    {
-	        count=count+colCover[j];
-	    }
-		
-		if (count>=mask.length)	//Should be cost.length but ok, because mask has same dimensions.	
-	    {
-			step=7;
-		}
-	    else
-		{
-			step=4;
-		}
-	    	
-		return step;
-	}
-	public static int hg_step4(int step, double[][] cost, int[][] mask, int[] rowCover, int[] colCover, int[] zero_RC)
-	{
-		//What STEP 4 does:
-		//Find an uncovered zero in cost and prime it (if none go to step 6). Check for star in same row:
-		//if yes, cover the row and uncover the star's column. Repeat until no uncovered zeros are left
-		//and go to step 6. If not, save location of primed zero and go to step 5.
-		
-		int[] row_col = new int[2];	//Holds row and col of uncovered zero.
-		boolean done = false;
-		while (done == false)
-		{
-			row_col = findUncoveredZero(row_col, cost, rowCover, colCover);
-			if (row_col[0] == -1)
-			{
-				done = true;
-				step = 6;
-			}
-			else
-			{
-				mask[row_col[0]][row_col[1]] = 2;	//Prime the found uncovered zero.
-				
-				boolean starInRow = false;
-				for (int j=0; j<mask[row_col[0]].length; j++)
-				{
-					if (mask[row_col[0]][j]==1)		//If there is a star in the same row...
-					{
-						starInRow = true;
-						row_col[1] = j;		//remember its column.
-					}
-				}
-							
-				if (starInRow==true)	
-				{
-					rowCover[row_col[0]] = 1;	//Cover the star's row.
-					colCover[row_col[1]] = 0;	//Uncover its column.
-				}
-				else
-				{
-					zero_RC[0] = row_col[0];	//Save row of primed zero.
-					zero_RC[1] = row_col[1];	//Save column of primed zero.
-					done = true;
-					step = 5;
-				}
-			}
-		}
-		
-		return step;
-	}
-	public static int[] findUncoveredZero	//Aux 1 for hg_step4.
-	(int[] row_col, double[][] cost, int[] rowCover, int[] colCover)
-	{
-		row_col[0] = -1;	//Just a check value. Not a real index.
-		row_col[1] = 0;
-		
-		int i = 0; boolean done = false;
-		while (done == false)
-		{
-			int j = 0;
-			while (j < cost[i].length)
-			{
-				if (cost[i][j]==0 && rowCover[i]==0 && colCover[j]==0)
-				{
-					row_col[0] = i;
-					row_col[1] = j;
-					done = true;
-				}
-				j = j+1;
-			}//end inner while
-			i=i+1;
-			if (i >= cost.length)
-			{
-				done = true;
-			}
-		}//end outer while
-		
-		return row_col;
-	}
-	public static int hg_step5(int step, int[][] mask, int[] rowCover, int[] colCover, int[] zero_RC)
-	{
-		//What STEP 5 does:	
-		//Construct series of alternating primes and stars. Start with prime from step 4.
-		//Take star in the same column. Next take prime in the same row as the star. Finish
-		//at a prime with no star in its column. Unstar all stars and star the primes of the
-		//series. Erasy any other primes. Reset covers. Go to step 3.
-		
-		int count = 0;												//Counts rows of the path matrix.
-		int[][] path = new int[(mask[0].length*mask.length)][2];	//Path matrix (stores row and col).
-		path[count][0] = zero_RC[0];								//Row of last prime.
-		path[count][1] = zero_RC[1];								//Column of last prime.
-		
-		boolean done = false;
-		while (done == false)
-		{ 
-			int r = findStarInCol(mask, path[count][1]);
-			if (r>=0)
-			{
-				count = count+1;
-				path[count][0] = r;					//Row of starred zero.
-				path[count][1] = path[count-1][1];	//Column of starred zero.
-			}
-			else
-			{
-				done = true;
-			}
-			
-			if (done == false)
-			{
-				int c = findPrimeInRow(mask, path[count][0]);
-				count = count+1;
-				path[count][0] = path [count-1][0];	//Row of primed zero.
-				path[count][1] = c;					//Col of primed zero.
-			}
-		}//end while
-		
-		convertPath(mask, path, count);
-		clearCovers(rowCover, colCover);
-		erasePrimes(mask);
-		
-		step = 3;
-		return step;
-		
-	}
-	public static int findStarInCol			//Aux 1 for hg_step5.
-	(int[][] mask, int col)
-	{
-		int r=-1;	//Again this is a check value.
-		for (int i=0; i<mask.length; i++)
-		{
-			if (mask[i][col]==1)
-			{
-				r = i;
-			}
-		}
-				
-		return r;
-	}
-	public static int findPrimeInRow		//Aux 2 for hg_step5.
-	(int[][] mask, int row)
-	{
-		int c = -1;
-		for (int j=0; j<mask[row].length; j++)
-		{
-			if (mask[row][j]==2)
-			{
-				c = j;
-			}
-		}
-		
-		return c;
-	}
-	public static void convertPath			//Aux 3 for hg_step5.
-	(int[][] mask, int[][] path, int count)
-	{
-		for (int i=0; i<=count; i++)
-		{
-			if (mask[(path[i][0])][(path[i][1])]==1)
-			{
-				mask[(path[i][0])][(path[i][1])] = 0;
-			}
-			else
-			{
-				mask[(path[i][0])][(path[i][1])] = 1;
-			}
-		}
-	}
-	public static void erasePrimes			//Aux 4 for hg_step5.
-	(int[][] mask)
-	{
-		for (int i=0; i<mask.length; i++)
-		{
-			for (int j=0; j<mask[i].length; j++)
-			{
-				if (mask[i][j]==2)
-				{
-					mask[i][j] = 0;
-				}
-			}
-		}
-	}
-	public static void clearCovers			//Aux 5 for hg_step5 (and not only).
-	(int[] rowCover, int[] colCover)
-	{
-		for (int i=0; i<rowCover.length; i++)
-		{
-			rowCover[i] = 0;
-		}
-		for (int j=0; j<colCover.length; j++)
-		{
-			colCover[j] = 0;
-		}
-	}
-	public static int hg_step6(int step, double[][] cost, int[] rowCover, int[] colCover, double maxCost)
-	{
-		//What STEP 6 does:
-		//Find smallest uncovered value in cost: a. Add it to every element of covered rows
-		//b. Subtract it from every element of uncovered columns. Go to step 4.
-		
-		double minval = findSmallest(cost, rowCover, colCover, maxCost);
-		
-		for (int i=0; i<rowCover.length; i++)
-		{
-			for (int j=0; j<colCover.length; j++)
-			{
-				if (rowCover[i]==1)
-				{
-					cost[i][j] = cost[i][j] + minval;
-				}
-				if (colCover[j]==0)
-				{
-					cost[i][j] = cost[i][j] - minval;
-				}
-			}
-		}
-			
-		step = 4;
-		return step;
-	}
-	public static double findSmallest		//Aux 1 for hg_step6.
-	(double[][] cost, int[] rowCover, int[] colCover, double maxCost)
-	{
-		double minval = maxCost;				//There cannot be a larger cost than this.
-		for (int i=0; i<cost.length; i++)		//Now find the smallest uncovered value.
-		{
-			for (int j=0; j<cost[i].length; j++)
-			{
-				if (rowCover[i]==0 && colCover[j]==0 && (minval > cost[i][j]))
-				{
-					minval = cost[i][j];
-				}
-			}
-		}
-		
-		return minval;
-	}
-	
-	//***********//
-	//MAIN METHOD//
-	//***********//
-	
-	public static void main(String[] args) 
-	{
-		//Below enter "max" or "min" to find maximum sum or minimum sum assignment.
-		String sumType = "max";		
-				
-		//Hard-coded example.
-		//double[][] array =
-		//{
-		//		{1, 2, 3},
-		//		{2, 4, 6},
-		//		{3, 6, 9}
-		//};
-		
-		//<UNCOMMENT> BELOW AND COMMENT BLOCK ABOVE TO USE A RANDOMLY GENERATED MATRIX
-		int numOfRows = readInput("How many rows for the matrix? ");
-		int numOfCols = readInput("How many columns for the matrix? ");
-		double[][] array = new double[numOfRows][numOfCols];
-		generateRandomArray(array, "random");	//All elements within [0,1].
-		//</UNCOMMENT>
-		
-		if (array.length > array[0].length)
-		{
-			System.out.println("Array transposed (because rows>columns).\n");	//Cols must be >= Rows.
-			array = transpose(array);
-		}
-				
-		//<COMMENT> TO AVOID PRINTING THE MATRIX FOR WHICH THE ASSIGNMENT IS CALCULATED
-		System.out.println("\n(Printing out only 2 decimals)\n");
-		System.out.println("The matrix is:");
-		for (int i=0; i<array.length; i++)
-		{
-			for (int j=0; j<array[i].length; j++)
-				{System.out.printf("%.2f\t", array[i][j]);}
-			System.out.println();
-		}
-		System.out.println();
-		//</COMMENT>*/
-		
-		double startTime = System.nanoTime();	
-		int[][] assignment = new int[array.length][2];
-		assignment = hgAlgorithm(array, sumType);	//Call Hungarian algorithm.
-		double endTime = System.nanoTime();
-						
-		System.out.println("The winning assignment (" + sumType + " sum) is:\n");	
-		double sum = 0;
-		for (int i=0; i<assignment.length; i++)
-		{
-			//<COMMENT> to avoid printing the elements that make up the assignment
-			System.out.printf("array(%d,%d) = %.2f\n", (assignment[i][0]+1), (assignment[i][1]+1),
-					array[assignment[i][0]][assignment[i][1]]);
-			sum = sum + array[assignment[i][0]][assignment[i][1]];
-			//</COMMENT>
-		}
-		
-		System.out.printf("\nThe %s is: %.2f\n", sumType, sum);
-		printTime((endTime - startTime)/1000000000.0);
-		
-	}
-}
Index: applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/replacegeometry/ReplaceGeometryUtils.java
===================================================================
--- applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/replacegeometry/ReplaceGeometryUtils.java	(revision 28045)
+++ applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/replacegeometry/ReplaceGeometryUtils.java	(revision 28116)
@@ -1,4 +1,5 @@
 package org.openstreetmap.josm.plugins.utilsplugin2.replacegeometry;
 
+import edu.princeton.cs.algs4.AssignmentProblem;
 import java.awt.geom.Area;
 import java.awt.geom.Point2D;
@@ -264,5 +265,5 @@
         }
 
-        boolean useHungarian = Main.pref.getBoolean("utilsplugin2.replace-geometry.robustAssignment", false);
+        boolean useRobust = Main.pref.getBoolean("utilsplugin2.replace-geometry.robustAssignment", true);
         
         // Find new nodes that are closest to the old ones, remove matching old ones from the pool
@@ -270,8 +271,14 @@
         Map<Node, Node> nodeAssoc = new HashMap<Node, Node>();
         if (geometryPool.size() > 0 && nodePool.size() > 0) {
-            if (useHungarian) {  // use robust, but slower assignment
+            if (useRobust) {  // use robust, but slower assignment
                 int gLen = geometryPool.size();
                 int nLen = nodePool.size();
-                double cost[][] = new double[nLen][gLen];
+                int N = Math.max(gLen, nLen);
+                double cost[][] = new double[N][N];
+                for (int i = 0; i < N; i++) {
+                    for (int j = 0; j < N; j++) {
+                        cost[i][j] = Double.MAX_VALUE;
+                    }
+                }
 
                 double maxDistance = Double.parseDouble(Main.pref.get("utilsplugin2.replace-geometry.max-distance", "1"));
@@ -286,8 +293,8 @@
                     }
                 }
-                int[][] assignment = HungarianAlgorithm.hgAlgorithm(cost, "min");
-                for (int i = 0; i < nLen; i++) {
-                    int nIdx = assignment[i][0];
-                    int gIdx = assignment[i][1];
+                AssignmentProblem assignment = new AssignmentProblem(cost);
+                for (int i = 0; i < N; i++) {
+                    int nIdx = i;
+                    int gIdx = assignment.sol(i);
                     if (cost[nIdx][gIdx] != Double.MAX_VALUE) {
                         nodeAssoc.put(geometryPool.get(gIdx), nodePool.get(nIdx));
