Skip to content

Commit 0245629

Browse files
committed
MaxFlow
1 parent 29b4928 commit 0245629

File tree

2 files changed

+343
-0
lines changed

2 files changed

+343
-0
lines changed

MaxFlow/MaxFlow.java

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
class MaxFlow {
2+
public class CapEdge {
3+
private final int from, to;
4+
private long cap;
5+
private final int rev;
6+
CapEdge(int from, int to, long cap, int rev) {
7+
this.from = from;
8+
this.to = to;
9+
this.cap = cap;
10+
this.rev = rev;
11+
}
12+
public int getFrom() {return from;}
13+
public int getTo() {return to;}
14+
public long getCap() {return cap;}
15+
public long getFlow() {return g[to][rev].cap;}
16+
}
17+
18+
private static final long INF = Long.MAX_VALUE;
19+
20+
private final int n;
21+
private int m;
22+
private final java.util.ArrayList<CapEdge> edges;
23+
private final int[] count;
24+
private final CapEdge[][] g;
25+
26+
public MaxFlow(int n) {
27+
this.n = n;
28+
this.edges = new java.util.ArrayList<>();
29+
this.count = new int[n];
30+
this.g = new CapEdge[n][];
31+
}
32+
33+
public int addEdge(int from, int to, long cap) {
34+
vertexRangeCheck(from);
35+
vertexRangeCheck(to);
36+
capNonNegativeCheck(cap);
37+
CapEdge e = new CapEdge(from, to, cap, count[to]);
38+
count[from]++; count[to]++;
39+
edges.add(e);
40+
return m++;
41+
}
42+
43+
public CapEdge getEdge(int i) {
44+
edgeRangeCheck(i);
45+
return edges.get(i);
46+
}
47+
48+
public java.util.ArrayList<CapEdge> getEdges() {
49+
return edges;
50+
}
51+
52+
public void changeEdge(int i, long newCap, long newFlow) {
53+
edgeRangeCheck(i);
54+
capNonNegativeCheck(newCap);
55+
if (newFlow > newCap) {
56+
throw new IllegalArgumentException(
57+
String.format("Flow %d is greater than capacity %d.", newCap, newFlow)
58+
);
59+
}
60+
CapEdge e = edges.get(i);
61+
CapEdge er = g[e.to][e.rev];
62+
e.cap = newCap - newFlow;
63+
er.cap = newFlow;
64+
}
65+
66+
private void buildGraph() {
67+
for (int i = 0; i < n; i++) {
68+
g[i] = new CapEdge[count[i]];
69+
}
70+
int[] idx = new int[n];
71+
for (CapEdge e : edges) {
72+
g[e.to][idx[e.to]++] = new CapEdge(e.to, e.from, 0, idx[e.from]);
73+
g[e.from][idx[e.from]++] = e;
74+
}
75+
}
76+
77+
public long maxFlow(int s, int t) {
78+
return flow(s, t, INF);
79+
}
80+
81+
public long flow(int s, int t, long flowLimit) {
82+
vertexRangeCheck(s);
83+
vertexRangeCheck(t);
84+
buildGraph();
85+
long flow = 0;
86+
int[] level = new int[n];
87+
int[] que = new int[n];
88+
int[] iter = new int[n];
89+
while (true) {
90+
java.util.Arrays.fill(level, -1);
91+
dinicBFS(s, t, level, que);
92+
if (level[t] < 0) return flow;
93+
java.util.Arrays.fill(iter, 0);
94+
while (true) {
95+
long d = dinicDFS(t, s, flowLimit - flow, iter, level);
96+
if (d <= 0) break;
97+
flow += d;
98+
}
99+
}
100+
}
101+
102+
private void dinicBFS(int s, int t, int[] level, int[] que) {
103+
int hd = 0, tl = 0;
104+
que[tl++] = s;
105+
level[s] = 0;
106+
while (tl > hd) {
107+
int u = que[hd++];
108+
for (CapEdge e : g[u]) {
109+
int v = e.to;
110+
if (e.cap <= 0 || level[v] >= 0) continue;
111+
level[v] = level[u] + 1;
112+
if (v == t) return;
113+
que[tl++] = v;
114+
}
115+
}
116+
}
117+
118+
private long dinicDFS(int cur, int s, long f, int[] iter, int[] level) {
119+
if (cur == s) return f;
120+
long res = 0;
121+
while (iter[cur] < count[cur]) {
122+
CapEdge er = g[cur][iter[cur]++];
123+
int u = er.to;
124+
CapEdge e = g[u][er.rev];
125+
if (level[u] >= level[cur] || e.cap <= 0) continue;
126+
long d = dinicDFS(u, s, Math.min(f - res, e.cap), iter, level);
127+
if (d <= 0) continue;
128+
e.cap -= d;
129+
er.cap += d;
130+
res += d;
131+
if (res == f) break;
132+
}
133+
return res;
134+
}
135+
136+
public long fordFulkersonMaxFlow(int s, int t) {
137+
return fordFulkersonFlow(s, t, INF);
138+
}
139+
140+
public long fordFulkersonFlow(int s, int t, long flowLimit) {
141+
vertexRangeCheck(s);
142+
vertexRangeCheck(t);
143+
buildGraph();
144+
boolean[] used = new boolean[n];
145+
long flow = 0;
146+
while (true) {
147+
java.util.Arrays.fill(used, false);
148+
long f = fordFulkersonDFS(s, t, flowLimit - flow, used);
149+
if (f <= 0) return flow;
150+
flow += f;
151+
}
152+
}
153+
154+
private long fordFulkersonDFS(int cur, int t, long f, boolean[] used) {
155+
if (cur == t) return f;
156+
used[cur] = true;
157+
for (CapEdge e : g[cur]) {
158+
if (used[e.to] || e.cap <= 0) continue;
159+
long d = fordFulkersonDFS(e.to, t, Math.min(f, e.cap), used);
160+
if (d <= 0) continue;
161+
e.cap -= d;
162+
g[e.to][e.rev].cap += d;
163+
return d;
164+
}
165+
return 0;
166+
}
167+
168+
public boolean[] minCut(int s) {
169+
vertexRangeCheck(s);
170+
boolean[] reachable = new boolean[n];
171+
int[] stack = new int[n];
172+
int ptr = 0;
173+
stack[ptr++] = s;
174+
reachable[s] = true;
175+
while (ptr > 0) {
176+
int u = stack[--ptr];
177+
for (CapEdge e : g[u]) {
178+
int v = e.to;
179+
if (reachable[v] || e.cap <= 0) continue;
180+
reachable[v] = true;
181+
stack[ptr++] = v;
182+
}
183+
}
184+
return reachable;
185+
}
186+
187+
private void vertexRangeCheck(int i) {
188+
if (i < 0 || i >= n) {
189+
throw new IndexOutOfBoundsException(
190+
String.format("Index %d out of bounds for length %d", i, n)
191+
);
192+
}
193+
}
194+
195+
private void edgeRangeCheck(int i) {
196+
if (i < 0 || i >= m) {
197+
throw new IndexOutOfBoundsException(
198+
String.format("Index %d out of bounds for length %d", i, m)
199+
);
200+
}
201+
}
202+
203+
private void capNonNegativeCheck(long cap) {
204+
if (cap < 0) {
205+
throw new IllegalArgumentException(
206+
String.format("Capacity %d is negative.", cap)
207+
);
208+
}
209+
}
210+
}

MaxFlow/Readme.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# クラス MaxFlow
2+
3+
## コンストラクタ
4+
5+
```java
6+
public MaxFlow(int n)
7+
```
8+
9+
`n` 頂点 `0` 辺のグラフを作る。
10+
11+
計算量
12+
13+
$O(n)$
14+
15+
## メソッド
16+
17+
### addEdge
18+
19+
```java
20+
public void addEdge(int from, int to, long cap)
21+
```
22+
23+
`from` から `to` へ最大容量 `cap`、流量 0 の辺を追加し、何番目に追加された辺かを返す。
24+
25+
制約
26+
27+
- `0 <= from, to < n`
28+
- `0 <= cap`
29+
30+
計算量
31+
32+
ならし $O(1)$
33+
34+
### maxFlow
35+
36+
```java
37+
// (1)
38+
public long maxFlow(int s, int t)
39+
// (2)
40+
public long flow(int s, int t, long flowLimit)
41+
// (3)
42+
public long fordFulkersonMaxFlow(int s, int t)
43+
// (4)
44+
public long fordFulkersonFlow(int s, int t, long flowLimit)
45+
```
46+
47+
- (1): 頂点 `s` から `t` へ流せる限り流し、流せた量を返す。Dinic のアルゴルズムを用います。
48+
- (2) 頂点 `s` から `t` へ流量 `flowLimit` に達するまで流せる限り流し、流せた量を返す。Dinic のアルゴルズムを用います。
49+
- (3) 頂点 `s` から `t` へ流せる限り流し、流せた量を返す。FordFulkerson のアルゴルズムを用います。
50+
- (4) 頂点 `s` から `t` へ流量 `flowLimit` に達するまで流せる限り流し、流せた量を返す。FordFulkerson のアルゴルズムを用います。
51+
- 複数回呼んだ場合は,前回流したフローからの差分が返ります。
52+
53+
制約
54+
55+
- `0 <= s, t < n`
56+
57+
計算量
58+
59+
`m` を追加された辺数として
60+
61+
- (1), (2) $O(\min(n^{2/3}*m, m^{3/2}))$ (辺の容量がすべて 1 の時)
62+
- (1), (2) $O(n^2*m)$
63+
- (3), (4) 返り値を `f` として,`O(f*m)`
64+
65+
### minCut
66+
67+
```java
68+
public boolean[] minCut(int s)
69+
```
70+
71+
長さ `n``boolean` 配列を返す。`i` 番目の要素は、頂点 `s` から `i` へ残余グラフで到達可能なとき、またその時のみ `true`。maxFlow(s, t) をちょうど一回呼んだ後に呼ぶと、返り値は `s`, `t` 間の mincut に対応します。
72+
73+
計算量
74+
75+
`m` を追加された辺数として $O(n+m)$
76+
77+
### getEdge / getEdges
78+
79+
`getEdge``getEdges` の返り値には以下のメソッドを持つ `MaxFlow.CapEdge` 型が用いられています。
80+
81+
```java
82+
class CapEdge {
83+
// (1)
84+
public int getFrom()
85+
// (2)
86+
public int getTO()
87+
// (3)
88+
public int getCap()
89+
// (4)
90+
public int getFlow()
91+
};
92+
```
93+
94+
- (1): 始点を返します。計算量: $O(1)$
95+
- (2): 終点を返します。計算量: $O(1)$
96+
- (3): 現在の容量を返します。計算量: $O(1)$
97+
- (4): 現在の流量を返しまず。計算量: $O(1)$
98+
99+
```java
100+
// (1)
101+
public CapEdge getEdge(int i)
102+
// (2)
103+
public java.util.ArrayList<CapEdge> getEdges()
104+
```
105+
106+
今の内部の辺の状態を返す。辺の順番は `addEdge` で追加された順番と同一。
107+
108+
制約
109+
110+
- (1): 追加した辺の数を `m` として,`0 <= i < m`
111+
112+
計算量
113+
114+
`m` を追加された辺数として
115+
116+
- (1): $O(1)$
117+
- (2): $O(1)$
118+
119+
### changeEdge
120+
121+
```java
122+
public void changeEdge(int i, long newCap, long newFlow)
123+
```
124+
125+
`i` 番目に変更された辺の容量、流量を `newCap`, `newFlow` に変更する。他の辺の容量、流量は変更しない。
126+
127+
制約
128+
129+
- `0 <= newFlow <= newCap`
130+
131+
計算量
132+
133+
$O(1)

0 commit comments

Comments
 (0)