最小费用最大流量 Java

61 阅读1分钟

最小费用最大流量


class Solution {
    static class Edge {
        int to, rid, cap, cost;
        Edge(int to, int rid, int cap, int cost) {
            this.to = to;
            this.rid = rid;
            this.cap = cap;
            this.cost = cost;
        }
    }

    public int minimumMoves(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int src = m * n;   // 超级源点
        int dst = src + 1; // 超级汇点
        List<List<Edge>> g = new ArrayList<>(m * n + 2);
        for (int i = 0; i < m * n + 2; i++) {
            g.add(new ArrayList<>());
        }
        
        
        for (int x = 0; x < m; x++) {
            for (int y = 0; y < n; y++) {
                int v = grid[x][y];
                if (v > 1) {
                    addEdge(g, src, x * n + y, v - 1, 0);
                    for (int i = 0; i < m; i++) {
                        for (int j = 0; j < n; j++) {
                            if (grid[i][j] == 0) {
                                addEdge(g, x * n + y, i * n + j, 1, Math.abs(x - i) + Math.abs(y - j));
                            }
                        }
                    }
                } else if (v == 0) {
                    addEdge(g, x * n + y, dst, 1, 0);
                }
            }
        }

        final int inf = (int) 1e9;
        int[] dist = new int[g.size()];
        boolean[] inQ = new boolean[g.size()];
        int[] fa = new int[g.size()];
        int[] fi = new int[g.size()];

        int[] result = ek(g, src, dst, dist, fa, fi, inf);
        return result[1];
    }

    private void addEdge(List<List<Edge>> g, int from, int to, int cap, int cost) {
        g.get(from).add(new Edge(to, g.get(to).size(), cap, cost));
        g.get(to).add(new Edge(from, g.get(from).size() - 1, 0, -cost));
    }

    private boolean spfa(List<List<Edge>> g, int src, int dst, int[] dist, int[] fa, int[] fi, int inf) {
        Arrays.fill(dist, inf);
        dist[src] = 0;
        boolean[] inQ = new boolean[g.size()];
        Queue<Integer> q = new LinkedList<>();
        q.offer(src);
        inQ[src] = true;

        while (!q.isEmpty()) {
            int v = q.poll();
            inQ[v] = false;
            for (int i = 0; i < g.get(v).size(); i++) {
                Edge e = g.get(v).get(i);
                if (e.cap > 0 && dist[v] + e.cost < dist[e.to]) {
                    dist[e.to] = dist[v] + e.cost;
                    fa[e.to] = v;
                    fi[e.to] = i;
                    if (!inQ[e.to]) {
                        q.offer(e.to);
                        inQ[e.to] = true;
                    }
                }
            }
        }
        return dist[dst] < inf;
    }

    private int[] ek(List<List<Edge>> g, int src, int dst, int[] dist, int[] fa, int[] fi, int inf) {
        int maxFlow = 0, minCost = 0;
        while (spfa(g, src, dst, dist, fa, fi, inf)) {
            int minF = inf;
            for (int v = dst; v != src; v = fa[v]) {
                Edge e = g.get(fa[v]).get(fi[v]);
                minF = Math.min(minF, e.cap);
            }

            for (int v = dst; v != src; v = fa[v]) {
                Edge e = g.get(fa[v]).get(fi[v]);
                e.cap -= minF;
                g.get(e.to).get(e.rid).cap += minF;
            }

            maxFlow += minF;
            minCost += dist[dst] * minF;
        }
        return new int[]{maxFlow, minCost};
    }