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;
}
}