diff --git a/cpp/graphs/flows/min_cost_flow_dijkstra.cpp b/cpp/graphs/flows/min_cost_flow_dijkstra.cpp index c0954ad9..3b8b79b3 100644 --- a/cpp/graphs/flows/min_cost_flow_dijkstra.cpp +++ b/cpp/graphs/flows/min_cost_flow_dijkstra.cpp @@ -1,5 +1,7 @@ #include +#include "../../structures/binary_heap_indexed.h" + using namespace std; // https://cp-algorithms.com/graph/min_cost_flow.html in O(E * V + E * logV * FLOW) @@ -49,27 +51,30 @@ struct min_cost_flow { } } - void dijkstra(int s, vector &pot, vector &dist, vector &curflow, vector &prevnode, - vector &prevedge) { - priority_queue, vector>, greater<>> q; - q.emplace(0, s); + void dijkstra(int s, int t, vector &pot, vector &dist, vector &finished, vector &curflow, + vector &prevnode, vector &prevedge) { + binary_heap_indexed h(graph.size()); + h.add(s, 0); fill(dist.begin(), dist.end(), numeric_limits::max()); dist[s] = 0; curflow[s] = numeric_limits::max(); - while (!q.empty()) { - auto [d, u] = q.top(); - q.pop(); - if (d != dist[u]) - continue; + fill(finished.begin(), finished.end(), false); + while (!finished[t] && h.size != 0) { + int u = h.remove_min(); + finished[u] = true; for (size_t i = 0; i < graph[u].size(); i++) { Edge &e = graph[u][i]; - int v = e.to; - if (e.cap <= e.f) + if (e.f >= e.cap) continue; + int v = e.to; int nprio = dist[u] + e.cost + pot[u] - pot[v]; + if (dist[v] > nprio) { + if (dist[v] == numeric_limits::max()) + h.add(v, nprio); + else + h.changePriority(v, nprio); dist[v] = nprio; - q.emplace(nprio, v); prevnode[v] = u; prevedge[v] = i; curflow[v] = min(curflow[u], e.cap - e.f); @@ -81,15 +86,17 @@ struct min_cost_flow { tuple cal_min_cost_flow(int s, int t, int maxf) { size_t n = graph.size(); vector pot(n), curflow(n), dist(n), prevnode(n), prevedge(n); + vector finished(n); bellman_ford(s, pot); // this can be commented out if edges costs are non-negative int flow = 0; int flow_cost = 0; while (flow < maxf) { - dijkstra(s, pot, dist, curflow, prevnode, prevedge); + dijkstra(s, t, pot, dist, finished, curflow, prevnode, prevedge); if (dist[t] == numeric_limits::max()) break; for (size_t i = 0; i < n; i++) - pot[i] += dist[i]; + if (finished[i]) + pot[i] += dist[i] - dist[t]; int df = min(curflow[t], maxf - flow); flow += df; for (int v = t; v != s; v = prevnode[v]) { diff --git a/cpp/structures/binary_heap_indexed.cpp b/cpp/structures/binary_heap_indexed.cpp new file mode 100644 index 00000000..ac4b430f --- /dev/null +++ b/cpp/structures/binary_heap_indexed.cpp @@ -0,0 +1,18 @@ +#include "binary_heap_indexed.h" + +#include + +using namespace std; + +// usage example +int main() { + binary_heap_indexed h(5); + h.add(0, 50); + h.add(1, 30); + h.add(2, 40); + h.changePriority(0, 20); + h.remove(1); + while (h.size) { + cout << h.remove_min() << endl; + } +} diff --git a/cpp/structures/binary_heap.cpp b/cpp/structures/binary_heap_indexed.h similarity index 83% rename from cpp/structures/binary_heap.cpp rename to cpp/structures/binary_heap_indexed.h index ed997a0d..4f3102e5 100644 --- a/cpp/structures/binary_heap.cpp +++ b/cpp/structures/binary_heap_indexed.h @@ -3,15 +3,15 @@ using namespace std; template -struct binary_heap { +struct binary_heap_indexed { vector heap; vector pos2Id; vector id2Pos; int size; - binary_heap() : size(0) {} + binary_heap_indexed() : size(0) {} - binary_heap(int n) : heap(n), pos2Id(n), id2Pos(n), size(0) {} + binary_heap_indexed(int n) : heap(n), pos2Id(n), id2Pos(n), size(0) {} void add(int id, T value) { heap[size] = value; @@ -78,16 +78,3 @@ struct binary_heap { id2Pos[pos2Id[j]] = j; } }; - -// usage example -int main() { - binary_heap h(5); - h.add(0, 50); - h.add(1, 30); - h.add(2, 40); - h.changePriority(0, 20); - h.remove(1); - while (h.size) { - cout << h.remove_min() << endl; - } -} diff --git a/java/graphs/flows/MinCostFlowDijkstra.java b/java/graphs/flows/MinCostFlowDijkstra.java index 20e240fb..ad93b658 100644 --- a/java/graphs/flows/MinCostFlowDijkstra.java +++ b/java/graphs/flows/MinCostFlowDijkstra.java @@ -2,6 +2,7 @@ import java.util.*; import java.util.stream.Stream; +import structures.BinaryHeapIndexed; // https://cp-algorithms.com/graph/min_cost_flow.html in O(E * V + min(E * logV * FLOW, V^2 * FLOW)) // negative-cost edges are allowed @@ -13,7 +14,7 @@ public MinCostFlowDijkstra(int nodes) { graph = Stream.generate(ArrayList::new).limit(nodes).toArray(List[] ::new); } - class Edge { + static class Edge { int to, rev, cap, f, cost; Edge(int to, int rev, int cap, int cost) { @@ -57,20 +58,16 @@ void bellmanFord(int s, int[] dist) { } } - void dijkstra( + void dijkstraSparse( int s, int t, int[] pot, int[] dist, boolean[] finished, int[] curflow, int[] prevnode, int[] prevedge) { - PriorityQueue q = new PriorityQueue<>(); - q.add((long) s); + BinaryHeapIndexed h = new BinaryHeapIndexed(graph.length); + h.add(s, 0); Arrays.fill(dist, Integer.MAX_VALUE); dist[s] = 0; Arrays.fill(finished, false); curflow[s] = Integer.MAX_VALUE; - while (!finished[t] && !q.isEmpty()) { - long cur = q.remove(); - int u = (int) (cur & 0xFFFF_FFFFL); - int priou = (int) (cur >>> 32); - if (priou != dist[u]) - continue; + while (!finished[t] && h.size != 0) { + int u = h.removeMin(); finished[u] = true; for (int i = 0; i < graph[u].size(); i++) { Edge e = graph[u].get(i); @@ -79,8 +76,11 @@ void dijkstra( int v = e.to; int nprio = dist[u] + e.cost + pot[u] - pot[v]; if (dist[v] > nprio) { + if (dist[v] == Integer.MAX_VALUE) + h.add(v, nprio); + else + h.changePriority(v, nprio); dist[v] = nprio; - q.add(((long) nprio << 32) + v); prevnode[v] = u; prevedge[v] = i; curflow[v] = Math.min(curflow[u], e.cap - e.f); @@ -89,7 +89,7 @@ void dijkstra( } } - void dijkstra2( + void dijkstraDense( int s, int t, int[] pot, int[] dist, boolean[] finished, int[] curflow, int[] prevnode, int[] prevedge) { Arrays.fill(dist, Integer.MAX_VALUE); dist[s] = 0; @@ -133,8 +133,8 @@ public int[] minCostFlow(int s, int t, int maxf) { int flow = 0; int flowCost = 0; while (flow < maxf) { - dijkstra(s, t, pot, dist, finished, curflow, prevnode, prevedge); // E*logV - // dijkstra2(s, t, pot, dist, finished, curflow, prevnode, prevedge); // V^2 + dijkstraSparse(s, t, pot, dist, finished, curflow, prevnode, prevedge); // O(E*logV) + // dijkstraDense(s, t, pot, dist, finished, curflow, prevnode, prevedge); // O(V^2) if (dist[t] == Integer.MAX_VALUE) break; for (int i = 0; i < n; i++) diff --git a/java/structures/BinaryHeapIndexed.java b/java/structures/BinaryHeapIndexed.java index 8822e6a7..17a71cec 100644 --- a/java/structures/BinaryHeapIndexed.java +++ b/java/structures/BinaryHeapIndexed.java @@ -3,18 +3,18 @@ // https://en.wikipedia.org/wiki/Binary_heap // invariant: heap[parent] <= heap[child] public class BinaryHeapIndexed { - long[] heap; + int[] heap; int[] pos2Id; int[] id2Pos; - int size; + public int size; public BinaryHeapIndexed(int n) { - heap = new long[n]; + heap = new int[n]; pos2Id = new int[n]; id2Pos = new int[n]; } - public void add(int id, long value) { + public void add(int id, int value) { heap[size] = value; pos2Id[size] = id; id2Pos[id] = size; @@ -30,14 +30,14 @@ public int removeMin() { return removedId; } - public void removeMin(int id) { + public void remove(int id) { int pos = id2Pos[id]; pos2Id[pos] = pos2Id[--size]; id2Pos[pos2Id[pos]] = pos; changePriority(pos2Id[pos], heap[size]); } - public void changePriority(int id, long value) { + public void changePriority(int id, int value) { int pos = id2Pos[id]; if (heap[pos] < value) { heap[pos] = value; @@ -73,12 +73,12 @@ void down(int pos) { } void swap(int i, int j) { - long tt = heap[i]; + int t = heap[i]; heap[i] = heap[j]; - heap[j] = tt; - int t = pos2Id[i]; + heap[j] = t; + int tt = pos2Id[i]; pos2Id[i] = pos2Id[j]; - pos2Id[j] = t; + pos2Id[j] = tt; id2Pos[pos2Id[i]] = i; id2Pos[pos2Id[j]] = j; } @@ -92,7 +92,7 @@ public static void main(String[] args) { heap.changePriority(1, 3); heap.changePriority(2, 6); - heap.removeMin(0); + heap.remove(0); // print elements in sorted order while (heap.size != 0) {