private void relabelToFront() {
   assert (!V.isEmpty()) : "No vertices";
   ListIterator<Vertex> iter = V.listIterator();
   while (iter.hasNext()) {
     Vertex v = iter.next();
     // System.out.println("Considering vertex: " + v);
     int oldHeight = v.getHeight();
     discharge(v);
     if (v.getHeight() > oldHeight) {
       iter.remove();
       V.addFirst(v);
       iter = V.listIterator(1);
     }
   }
 }
  private void relabel(Vertex u) {
    // System.out.println("Relabeling " + u);
    assert (u.getExcess() > 0) : "u not overflowing";

    List<Vertex> neighbors = u.getNeighbors();
    int minHeight = Integer.MAX_VALUE;
    for (Vertex v : neighbors) {
      int residCapacity = getResidualCapacity(u, v);
      assert (residCapacity == 0 || u.getHeight() <= v.getHeight());
      if (residCapacity > 0) {
        int partnerHeight = v.getHeight();
        minHeight = partnerHeight < minHeight ? partnerHeight : minHeight;
      }
    }
    u.setHeight(1 + minHeight);
  }
  private void discharge(Vertex u) {
    // System.out.println("Discharging " + u);
    while (u.getExcess() > 0) {
      if (u.getCurrNeighbor() >= u.getNumNeighbors()) {
        relabel(u);
        u.setCurrNeighbor(0);
      } else {
        Vertex v = u.getNeighbor(u.getCurrNeighbor());

        if (getResidualCapacity(u, v) > 0 && u.getHeight() == v.getHeight() + 1) {
          push(u, v);
        } else {
          u.incNextNeighbor();
        }
      }
    }
  }
  // Push-relabel methods
  // Push() pushes flow forwards, or decreases incoming flow
  private void push(Vertex u, Vertex v) {
    // System.out.println("Pushing from " + u + " to " + v);
    int excess = u.getExcess();
    int residualCapacity = getResidualCapacity(u, v);

    assert (excess > 0) : "Excess <= 0";
    assert (residualCapacity > 0) : "Resid capacity <= 0";
    assert (u.getHeight() == v.getHeight() + 1) : "Height of u != height of v + 1";

    int changeInFlow = excess < residualCapacity ? excess : residualCapacity;

    if (flowsForward(u, v)) {
      addToFlow(u, v, changeInFlow);
    } else {
      addToFlow(v, u, -changeInFlow);
    }

    u.addToExcess(-changeInFlow);
    v.addToExcess(changeInFlow);
  }