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);
  }
  private void setupSourceSide(Set<Employee> emps) {
    for (Employee e : emps) {
      Vertex u = Vertex.vertexFromEmployee(e);
      LV.add(u);

      source.addToNeighbors(u);
      u.addToNeighbors(source);

      setCapacity(source, u, 1);
      setFlow(source, u, 1);
      u.setExcess(1);

      // Prioritize friend for initial flow
      if (e.getId() == ProjectParams.FRIEND_ID) {
        V.addFirst(u);
      } else {
        V.add(u);
      }
    }

    source.setExcess(source.getExcess() - source.getNumNeighbors());
  }