/** * Solution to the ride hailing problem using Dinic's algorithm * for maximum bipartite matching. * The idea is that you want to re-use the drivers as much as possible. * We have two vertices for each request--one set of starting requests, * one set of next requests. We add an edge from starting request i to * next request j if it is possible for a single driver to serve request * j after serving request i. Choosing an edge to be in the matching * corresponds to re-using a driver for consecutive requests. * The answer is then the number of requests minus the number of edges * in the matching. * * @author Finn Lidbetter */ import java.util.*; import java.io.*; public class DinicRideHailing { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringBuilder sb = new StringBuilder(); String[] s = br.readLine().split(" "); int n = Integer.parseInt(s[0]); int m = Integer.parseInt(s[1]); int k = Integer.parseInt(s[2]); Integer[][] apsp = new Integer[n][n]; for (int i=0; i[] graph = createGraph(2*k+2); for (int i=0; i[] createGraph(int nodes) { List[] graph = new List[nodes]; for (int i = 0; i < nodes; i++) graph[i] = new ArrayList<>(); return graph; } static void addEdge(List[] graph, int u, int v, double cap) { graph[u].add(new Edge(v, graph[v].size(), cap)); graph[v].add(new Edge(u, graph[u].size() - 1, 0)); } static double maxFlow(List[] graph, int src, int dest) { double flow = 0; int[] dist = new int[graph.length]; while (dinicBfs(graph, src, dest, dist)) { int[] ptr = new int[graph.length]; while (true) { double df = dinicDfs(graph, ptr, dist, dest, src, Double.MAX_VALUE); if (df == 0) break; flow += df; } } return flow; } static boolean dinicBfs(List[] graph, int src, int dest, int[] dist) { Arrays.fill(dist, -1); dist[src] = 0; int[] q = new int[graph.length]; int size = 0; q[size++] = src; for (int i = 0; i < size; i++) for (Edge e : graph[q[i]]) if (dist[e.v] < 0 && e.f < e.cap) { dist[e.v] = dist[q[i]] + 1; q[size++] = e.v; } return dist[dest] >= 0; } static double dinicDfs(List[] graph, int[] ptr, int[] dist, int dest, int u, double f) { if (u == dest) return f; for (; ptr[u] < graph[u].size(); ++ptr[u]) { Edge e = graph[u].get(ptr[u]); if (dist[e.v] == dist[u] + 1 && e.f < e.cap) { double df = dinicDfs(graph, ptr, dist, dest, e.v, Math.min(f, e.cap - e.f)); if (df > 0) { e.f += df; graph[e.v].get(e.rev).f -= df; return df; } } } return 0; } static class Edge { int v, rev; double cap, f; public Edge(int v, int rev, double cap) { this.v = v; this.rev = rev; this.cap = cap; } } }