Software Development Engineer @ Amazon
reniowood at gmail.com resume
  public class FlowNetwork {
  private static class Edge {
      int u, v, capacity, flow;
      Edge reverse; // 역방향 edge
      public Edge(int u, int v, int capacity) {
          this.u = u;
          this.v = v;
          this.capacity = capacity;
          this.flow = 0;
          this.reverse = null;
      }
  }
  private int N; // network node의 갯수
  private List[] network; // List<Edge>의 배열. 인접 리스트
  private int source, sink; // source, sink node의 index
  // queue를 이용해 BFS를 실행한다.
  private Edge[] findPath() {
      Edge[] edges = new Edge[N];
      Queue<Integer> queue = new LinkedList<>();
      queue.offer(source);
      while (!queue.isEmpty()) {
          int currNode = queue.poll();
          for (Edge edge : (List<Edge>) network[currNode]) {
              int nextNode = edge.v;
              // 아직 capacity가 여유 있는 edge를 찾는다.
              if (edge.capacity - edge.flow > 0 &&
                  edges[nextNode] == null &&
                  nextNode != source) {
                      queue.offer(nextNode);
                  edges[nextNode] = edge;
              }
          }
      }
      return edges;
  }
  public int findMaxFlow() {
      int maxFlow = 0;
      while (true) {
          // BFS를 이용해 augmenting path를 찾는다.
          // edge[v]는 v를 항햔 edge를 나타낸다. (edge.v == v)
          Edge[] edges = findPath();
          if (edges[sink] == null) {
              break;
          }
          // augmenting path에 흐르는 flow 값을 찾는다.
          int flow = Integer.MAX_VALUE;
          for (Edge edge = edges[sink]; edge != null; edge = edges[edge.u]) {
              flow = Math.min(flow, edge.capacity - edge.flow);
          }
          // 찾은 flow를 흘려준다.
          for (Edge edge = edges[sink]; edge != null; edge = edges[edge.u]) {
              edge.flow += flow;
              edge.rev.flow -= flow;
          }
          // 이번에 찾은 flow를 더해준다.
          maxFlow += flow;
      }
      return maxFlow;
  }
  }
      public class FlowNetwork {
          private static class Edge {
              int u, v, capacity, cost, flow;
              Edge reverse; // 역방향 edge
              public Edge(int u, int v, int capacity, int cost) {
                  this.u = u;
                  this.v = v;
                  this.capacity = capacity;
                  this.cost = cost;
                  this.flow = 0;
                  this.reverse = null;
              }
          }
          private int N; // network node의 갯수
          private List[] network; // List<Edge>의 배열. 인접 리스트
          private int source, sink; // source, sink node의 index
          // queue를 이용해 BFS를 실행한다.
          private Edge[] findMinCostPath() {
              Edge[] edges = new Edge[N];
              Queue<Integer> queue = new LinkedList<>();
              // node가 queue에 들어있는지 O(1)에 확인하기 위한 boolean 배열
              boolean[] isInQueue = new boolean[N];
              // source로부터 각 node로의 minimum cost가 들어있는 배열
              int[] distances = new int[N];
              Arrays.fill(distances, Integer.MAX_VALUE);
              queue.offer(source);
              isInQueue[source] = true;
              distances[source] = 0;
              while (!queue.isEmpty()) {
                  int currNode = queue.poll();
                  isInQueue[currNode] = false;
                  for (Edge edge : (List<Edge>) network[currNode]) {
                      int nextNode = edge.v;
                      // 아직 capacity가 여유 있는 edge를 찾는다.
                      if (edge.capacity - edge.flow > 0 &&
                          distances[currNode] + edge.cost < distances[nextNode]) {
                          distances[nextNode] = distances[currNode] + edge.cost;
                          edges[nextNode] = edge;
                          if (!isInQueue[nextNode]) {
                              queue.offer(nextNode);
                              isInQueue[nextNode] = true;
                          }
                      }
                  }
              }
              return edges;
          }
          public int findMaxFlow() {
              int maxFlow = 0;
              while (true) {
                  // BFS를 이용해 augmenting path를 찾는다.
                  // edge[v]는 v를 항햔 edge를 나타낸다. (edge.v == v)
                  Edge[] edges = findMinCostPath();
                  if (edges[sink] == null) {
                      break;
                  }
                  // augmenting path에 흐르는 flow 값을 찾는다.
                  int flow = Integer.MAX_VALUE;
                  for (Edge edge = edges[sink]; edge != null; edge = edges[edge.u]) {
                      flow = Math.min(flow, edge.capacity - edge.flow);
                  }
                  // 찾은 flow를 흘려준다.
                  for (Edge edge = edges[sink]; edge != null; edge = edges[edge.u]) {
                      edge.flow += flow;
                      edge.rev.flow -= flow;
                  }
                  // 이번에 찾은 flow를 더해준다.
                  maxFlow += flow;
              }
              return maxFlow;
          }
      }