code: public double pushRelabel(double[][] flow, int source, int sink) {
          int[] seen = new int[n];
          int[] queue = new int[n-2];
          for (int i = 0, p = 0; i < n; i++) {
              if ((i != source) && (i != sink)) {
                  queue[p++] = i;
              }
          }
          
          int[] height = new int[n];//dijkstra(sink, false);
          height[source] = n;
          
          double[] excess = new double[n];
          excess[source] = Double.MAX_VALUE;
          
          for (int i = 0; i < n; i++) {
              push(flow, excess, source, i);
          }
  
          int p = 0;
          while (p < n-2) {
              int u = queue[p];
              double oldHeight = height[u];
              discharge(flow, excess, height, seen, u);
              if (height[u] > oldHeight) {
                  moveToFront(p, queue);
                  p = 0;
              } else {
                  p += 1;
              }
          }
          
          double maxflow = 0.0;
          for (int i = 0; i < n; i++) {
              maxflow += flow[source][i];
          }
  
          return maxflow;
      }
docs: Push-relabel algorithm for maximum flow