洛谷P3381 【模板】最小费用最大流
题目链接:https://www.luogu.com.cn/problem/P3381
代码实现
import java.io.*;import java.util.*;public class Main {// 图private static List<List<Edge>> graph;// 顶点数static int V;// 顶点的势static int[] h;// 到达目标结点的最短距离static int[] dist;// 最短路中的前驱节点static int[] prevV;// 最短路中的前驱节点对应的边static int[] prevE;public static void main(String[] args) throws IOException {StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));in.nextToken();int N = (int) in.nval;in.nextToken();int M = (int) in.nval;in.nextToken();int src = (int) in.nval;in.nextToken();int dst = (int) in.nval;V = N + 1;init();while (M-- > 0) {int from, to, capacity, cost;in.nextToken();from = (int) in.nval;in.nextToken();to = (int) in.nval;in.nextToken();capacity = (int) in.nval;in.nextToken();cost = (int) in.nval;addEgde(from, to, capacity, cost);}int[] ans = minCostFlow(src, dst);out.println(ans[0] + " " + ans[1]);out.flush();}private static void init() {graph = new ArrayList<List<Edge>>(V);for (int i = 0; i < V; ++i) {graph.add(new ArrayList<Edge>());}h = new int[V];dist = new int[V];prevV = new int[V];prevE = new int[V];}// 向图中增加一条从from到to的容量为cap费用为cost的边private static void addEgde(int from, int to, int cap, int cost) {graph.get(from).add(new Edge(to, cap, cost, graph.get(to).size()));graph.get(to).add(new Edge(from, 0, -cost, graph.get(from).size() - 1));}// 求解从s到t流量为f的最大容量最小费用流private static int[] minCostFlow(final int src, final int dst) {int res = 0;int flow = 0;Arrays.fill(h, 0);while (true) {// 使用Dijkstra算法更新hArrays.fill(dist, Integer.MAX_VALUE);dist[src] = 0;// int[0]存储最短距离// int[1]存储结点编号// 建立小根堆Comparator<int[]> comparator = new Comparator<int[]>() {public int compare(int[] o1, int[] o2) {return o1[0] - o2[0];}};Queue<int[]> queue = new PriorityQueue<int[]>(comparator);queue.offer(new int[]{0, src});while (!queue.isEmpty()) {int[] pair = queue.poll();int v = pair[1];if (dist[v] < pair[0]) {continue;}for (int i = 0; i < graph.get(v).size(); ++i) {Edge edge = graph.get(v).get(i);if ((edge.capacity > 0) && (dist[edge.to] > dist[v] + edge.cost + h[v] - h[edge.to])) {dist[edge.to] = dist[v] + edge.cost + h[v] - h[edge.to];prevV[edge.to] = v;prevE[edge.to] = i;queue.offer(new int[]{dist[edge.to], edge.to});}}}// 不能再增广if (dist[dst] == Integer.MAX_VALUE) {break;}for (int v = 0; v < V; ++v) {h[v] += dist[v];}// 找到路径上容量最小的边int minCapacity = Integer.MAX_VALUE;for (int v = dst; v != src; v = prevV[v]) {minCapacity = Math.min(minCapacity, graph.get(prevV[v]).get(prevE[v]).capacity);}// 沿s到t的最短路尽量增广// 计算残差网络flow += minCapacity;res += minCapacity * h[dst];for (int v = dst; v != src; v = prevV[v]) {Edge e = graph.get(prevV[v]).get(prevE[v]);e.capacity -= minCapacity;graph.get(v).get(e.reserve).capacity += minCapacity;}}return new int[]{flow, res};}}class Edge {int to;int capacity;int cost;int reserve;public Edge(int to, int capacity, int cost, int reserve) {this.to = to;this.capacity = capacity;this.cost = cost;this.reserve = reserve;}}
输入样例
4 5 4 34 2 30 24 3 20 32 3 20 12 1 30 91 3 40 5
输出样例
50 280
可行流最小费用
代码实现
import java.io.*;import java.util.*;public class Main {// 图private static List<List<Edge>> graph;// 顶点数static int V;// 顶点的势static int[] h;// 到达目标结点的最短距离static int[] dist;// 最短路中的前驱节点static int[] prevV;// 最短路中的前驱节点对应的边static int[] prevE;public static void main(String[] args) throws IOException {StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));in.nextToken();int N = (int) in.nval;in.nextToken();int M = (int) in.nval;in.nextToken();int src = (int) in.nval;in.nextToken();int dst = (int) in.nval;V = N + 1;init();while (M-- > 0) {int from, to, capacity, cost;in.nextToken();from = (int) in.nval;in.nextToken();to = (int) in.nval;in.nextToken();capacity = (int) in.nval;in.nextToken();cost = (int) in.nval;addEgde(from, to, capacity, cost);}int ans = minCostFlow(src, dst, 50);out.println(ans);out.flush();}private static void init() {graph = new ArrayList<List<Edge>>(V);for (int i = 0; i < V; ++i) {graph.add(new ArrayList<Edge>());}h = new int[V];dist = new int[V];prevV = new int[V];prevE = new int[V];}// 向图中增加一条从from到to的容量为cap费用为cost的边private static void addEgde(int from, int to, int cap, int cost) {graph.get(from).add(new Edge(to, cap, cost, graph.get(to).size()));graph.get(to).add(new Edge(from, 0, -cost, graph.get(from).size() - 1));}// 求解从s到t流量为f的最小费用流,如果没有流量为f的流,则返回-1private static int minCostFlow(final int src, final int dst, int flow) {int res = 0;Arrays.fill(h, 0);while (flow > 0) {// 使用Dijkstra算法更新hArrays.fill(dist, Integer.MAX_VALUE);dist[src] = 0;// int[0]存储最短距离// int[1]存储结点编号// 建立小根堆Comparator<int[]> comparator = new Comparator<int[]>() {public int compare(int[] o1, int[] o2) {return o1[0] - o2[0];}};Queue<int[]> queue = new PriorityQueue<int[]>(comparator);queue.offer(new int[]{0, src});while (!queue.isEmpty()) {int[] pair = queue.poll();int v = pair[1];if (dist[v] < pair[0]) {continue;}for (int i = 0; i < graph.get(v).size(); ++i) {Edge edge = graph.get(v).get(i);if ((edge.capacity > 0) && (dist[edge.to] > dist[v] + edge.cost + h[v] - h[edge.to])) {dist[edge.to] = dist[v] + edge.cost + h[v] - h[edge.to];prevV[edge.to] = v;prevE[edge.to] = i;queue.offer(new int[]{dist[edge.to], edge.to});}}}// 不能再增广if (dist[dst] == Integer.MAX_VALUE) {return -1;}for (int v = 0; v < V; ++v) {h[v] += dist[v];}// 找到路径上容量最小的边int minCapacity = Integer.MAX_VALUE;for (int v = dst; v != src; v = prevV[v]) {minCapacity = Math.min(minCapacity, graph.get(prevV[v]).get(prevE[v]).capacity);}// 沿s到t的最短路尽量增广// 计算残差网络flow -= minCapacity;res += minCapacity * h[dst];for (int v = dst; v != src; v = prevV[v]) {Edge e = graph.get(prevV[v]).get(prevE[v]);e.capacity -= minCapacity;graph.get(v).get(e.reserve).capacity += minCapacity;}}return res;}}class Edge {int to;int capacity;int cost;int reserve;public Edge(int to, int capacity, int cost, int reserve) {this.to = to;this.capacity = capacity;this.cost = cost;this.reserve = reserve;}}
样例输入
4 5 4 34 2 30 24 3 20 32 3 20 12 1 30 91 3 40 5
样例输出
280
