Skip to content
4 changes: 2 additions & 2 deletions 2SAT/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public boolean satisfiable()
### answer

```java
public java.util.BitSet answer()
public boolean[] answer()
```

`satisfiable` を最後に呼んだ時点での、クローズを満たす割当を返す。割当が存在しなかった場合は `null` を返す。
Expand All @@ -107,4 +107,4 @@ $O(n)$

## 使用例

[AtCoder Library Practice Contest H - Two SAT](https://atcoder.jp/contests/practice2/submissions/16603939)
[AtCoder Library Practice Contest H - Two SAT](https://atcoder.jp/contests/practice2/submissions/16647102)
11 changes: 7 additions & 4 deletions 2SAT/TwoSAT.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
/**
* @verified https://atcoder.jp/contests/practice2/submissions/16647102
*/
class TwoSAT {
private final int n;
private final InternalSCC scc;
private final java.util.BitSet answer;
private final boolean[] answer;

private boolean hasCalledSatisfiable = false;
private boolean existsAnswer = false;

public TwoSAT(int n) {
this.n = n;
this.scc = new InternalSCC(2 * n);
this.answer = new java.util.BitSet(n);
this.answer = new boolean[n];
}

public void addClause(int x, boolean f, int y, boolean g) {
Expand All @@ -30,12 +33,12 @@ public boolean satisfiable() {
int[] ids = scc.ids();
for (int i = 0; i < n; i++) {
if (ids[i << 1 | 0] == ids[i << 1 | 1]) return existsAnswer = false;
answer.set(i, ids[i << 1 | 0] < ids[i << 1 | 1]);
answer[i] = ids[i << 1 | 0] < ids[i << 1 | 1];
}
return existsAnswer = true;
}

public java.util.BitSet answer() {
public boolean[] answer() {
if (!hasCalledSatisfiable) {
throw new UnsupportedOperationException(
"Call TwoSAT#satisfiable at least once before TwoSAT#answer."
Expand Down
43 changes: 19 additions & 24 deletions MaxFlow/MaxFlow.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* @verified https://atcoder.jp/contests/practice2/tasks/practice2_d
*/
class MaxFlow {
public class CapEdge {
private final int from, to;
Expand Down Expand Up @@ -31,17 +34,17 @@ public MaxFlow(int n) {
}

public int addEdge(int from, int to, long cap) {
vertexRangeCheck(from);
vertexRangeCheck(to);
capNonNegativeCheck(cap);
rangeCheck(from, 0, n);
rangeCheck(to, 0, n);
nonNegativeCheck(cap, "Capacity");
CapEdge e = new CapEdge(from, to, cap, count[to]);
count[from]++; count[to]++;
edges.add(e);
return m++;
}

public CapEdge getEdge(int i) {
edgeRangeCheck(i);
rangeCheck(i, 0, m);
return edges.get(i);
}

Expand All @@ -50,8 +53,8 @@ public java.util.ArrayList<CapEdge> getEdges() {
}

public void changeEdge(int i, long newCap, long newFlow) {
edgeRangeCheck(i);
capNonNegativeCheck(newCap);
rangeCheck(i, 0, m);
nonNegativeCheck(newCap, "Capacity");
if (newFlow > newCap) {
throw new IllegalArgumentException(
String.format("Flow %d is greater than capacity %d.", newCap, newFlow)
Expand Down Expand Up @@ -79,8 +82,8 @@ public long maxFlow(int s, int t) {
}

public long flow(int s, int t, long flowLimit) {
vertexRangeCheck(s);
vertexRangeCheck(t);
rangeCheck(s, 0, n);
rangeCheck(t, 0, n);
buildGraph();
long flow = 0;
int[] level = new int[n];
Expand Down Expand Up @@ -138,8 +141,8 @@ public long fordFulkersonMaxFlow(int s, int t) {
}

public long fordFulkersonFlow(int s, int t, long flowLimit) {
vertexRangeCheck(s);
vertexRangeCheck(t);
rangeCheck(s, 0, n);
rangeCheck(t, 0, n);
buildGraph();
boolean[] used = new boolean[n];
long flow = 0;
Expand All @@ -166,7 +169,7 @@ private long fordFulkersonDFS(int cur, int t, long f, boolean[] used) {
}

public boolean[] minCut(int s) {
vertexRangeCheck(s);
rangeCheck(s, 0, n);
boolean[] reachable = new boolean[n];
int[] stack = new int[n];
int ptr = 0;
Expand All @@ -184,26 +187,18 @@ public boolean[] minCut(int s) {
return reachable;
}

private void vertexRangeCheck(int i) {
if (i < 0 || i >= n) {
private void rangeCheck(int i, int minInlusive, int maxExclusive) {
if (i < 0 || i >= maxExclusive) {
throw new IndexOutOfBoundsException(
String.format("Index %d out of bounds for length %d", i, n)
String.format("Index %d out of bounds for length %d", i, maxExclusive)
);
}
}

private void edgeRangeCheck(int i) {
if (i < 0 || i >= m) {
throw new IndexOutOfBoundsException(
String.format("Index %d out of bounds for length %d", i, m)
);
}
}

private void capNonNegativeCheck(long cap) {
private void nonNegativeCheck(long cap, java.lang.String attribute) {
if (cap < 0) {
throw new IllegalArgumentException(
String.format("Capacity %d is negative.", cap)
String.format("%s %d is negative.", attribute, cap)
);
}
}
Expand Down
8 changes: 3 additions & 5 deletions MaxFlow/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ class CapEdge {
// (1)
public int getFrom()
// (2)
public int getTO()
public int getTo()
// (3)
public int getCap()
public long getCap()
// (4)
public int getFlow()
public long getFlow()
};
```

Expand All @@ -111,8 +111,6 @@ public java.util.ArrayList<CapEdge> getEdges()

計算量

`m` を追加された辺数として

- (1): $O(1)$
- (2): $O(1)$

Expand Down
208 changes: 208 additions & 0 deletions MinCostFlow/MinCostFlow.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/**
* @verified
* - https://atcoder.jp/contests/practice2/tasks/practice2_e
* - http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_6_B
*/
class MinCostFlow {
public class WeightedCapEdge {
private final int from, to;
private long cap;
private long cost;
private final int rev;
WeightedCapEdge(int from, int to, long cap, long cost, int rev) {
this.from = from;
this.to = to;
this.cap = cap;
this.cost = cost;
this.rev = rev;
}
public int getFrom() {return from;}
public int getTo() {return to;}
public long getCap() {return cap;}
public long getCost() {return cost;}
public long getFlow() {return g[to][rev].cap;}
}

private static final long INF = Long.MAX_VALUE;

private final int n;
private int m;
private final java.util.ArrayList<WeightedCapEdge> edges;
private final int[] count;
private final WeightedCapEdge[][] g;
private final long[] potential;

private final long[] dist;
private final WeightedCapEdge[] prev;

public MinCostFlow(int n) {
this.n = n;
this.edges = new java.util.ArrayList<>();
this.count = new int[n];
this.g = new WeightedCapEdge[n][];
this.potential = new long[n];
this.dist = new long[n];
this.prev = new WeightedCapEdge[n];
}

public int addEdge(int from, int to, long cap, long cost) {
rangeCheck(from, 0, n);
rangeCheck(to, 0, n);
nonNegativeCheck(cap, "Capacity");
nonNegativeCheck(cost, "Cost");
WeightedCapEdge e = new WeightedCapEdge(from, to, cap, cost, count[to]);
count[from]++; count[to]++;
edges.add(e);
return m++;
}

private void buildGraph() {
for (int i = 0; i < n; i++) {
g[i] = new WeightedCapEdge[count[i]];
}
int[] idx = new int[n];
for (WeightedCapEdge e : edges) {
g[e.to][idx[e.to]++] = new WeightedCapEdge(e.to, e.from, 0, -e.cost, idx[e.from]);
g[e.from][idx[e.from]++] = e;
}
}

private long addFlow;
private long addCost;

public long[] minCostMaxFlow(int s, int t) {
return minCostFlow(s, t, INF);
}

public long[] minCostFlow(int s, int t, long flowLimit) {
rangeCheck(s, 0, n);
rangeCheck(t, 0, n);
if (s == t) {
throw new IllegalArgumentException(String.format("s = t = %d", s));
}
nonNegativeCheck(flowLimit, "Flow");
buildGraph();
long flow = 0;
long cost = 0;
while (true) {
dijkstra(s, t, flowLimit - flow);
if (addFlow == 0) break;
flow += addFlow;
cost += addFlow * addCost;
}
return new long[]{flow, cost};
}

public java.util.ArrayList<long[]> minCostSlope(int s, int t) {
return minCostSlope(s, t, INF);
}

public java.util.ArrayList<long[]> minCostSlope(int s, int t, long flowLimit) {
rangeCheck(s, 0, n);
rangeCheck(t, 0, n);
if (s == t) {
throw new IllegalArgumentException(String.format("s = t = %d", s));
}
nonNegativeCheck(flowLimit, "Flow");
buildGraph();
java.util.ArrayList<long[]> slope = new java.util.ArrayList<>();
long prevCost = -1;
long flow = 0;
long cost = 0;
while (true) {
slope.add(new long[]{flow, cost});
dijkstra(s, t, flowLimit - flow);
if (addFlow == 0) return slope;
flow += addFlow;
cost += addFlow * addCost;
if (addCost == prevCost) {
slope.remove(slope.size() - 1);
}
prevCost = addCost;
}
}

private void dijkstra(int s, int t, long maxFlow) {
final class State implements Comparable<State> {
final int v;
final long d;
State(int v, long d) {this.v = v; this.d = d;}
public int compareTo(State s) {return d == s.d ? v - s.v : d > s.d ? 1 : -1;}
}
java.util.Arrays.fill(dist, INF);
dist[s] = 0;
java.util.PriorityQueue<State> pq = new java.util.PriorityQueue<>();
pq.add(new State(s, 0l));
while (pq.size() > 0) {
State st = pq.poll();
int u = st.v;
if (st.d != dist[u]) continue;
for (WeightedCapEdge e : g[u]) {
if (e.cap <= 0) continue;
int v = e.to;
long nextCost = dist[u] + e.cost + potential[u] - potential[v];
if (nextCost < dist[v]) {
dist[v] = nextCost;
prev[v] = e;
pq.add(new State(v, dist[v]));
}
}
}
if (dist[t] == INF) {
addFlow = 0;
addCost = INF;
return;
}
for (int i = 0; i < n; i++) {
potential[i] += dist[i];
}
addCost = 0;
addFlow = maxFlow;
for (int v = t; v != s;) {
WeightedCapEdge e = prev[v];
addCost += e.cost;
addFlow = java.lang.Math.min(addFlow, e.cap);
v = e.from;
}
for (int v = t; v != s;) {
WeightedCapEdge e = prev[v];
e.cap -= addFlow;
g[v][e.rev].cap += addFlow;
v = e.from;
}
}

public void clearFlow() {
java.util.Arrays.fill(potential, 0);
for (WeightedCapEdge e : edges) {
long flow = e.getFlow();
e.cap += flow;
g[e.to][e.rev].cap -= flow;
}
}

public WeightedCapEdge getEdge(int i) {
rangeCheck(i, 0, m);
return edges.get(i);
}

public java.util.ArrayList<WeightedCapEdge> getEdges() {
return edges;
}

private void rangeCheck(int i, int minInlusive, int maxExclusive) {
if (i < 0 || i >= maxExclusive) {
throw new IndexOutOfBoundsException(
String.format("Index %d out of bounds for length %d", i, maxExclusive)
);
}
}

private void nonNegativeCheck(long cap, java.lang.String attribute) {
if (cap < 0) {
throw new IllegalArgumentException(
String.format("%s %d is negative.", attribute, cap)
);
}
}
}
Loading