最小费用最大流量
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};
}