洛谷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算法更新h
Arrays.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 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 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的流,则返回-1
private static int minCostFlow(final int src, final int dst, int flow) {
int res = 0;
Arrays.fill(h, 0);
while (flow > 0) {
// 使用Dijkstra算法更新h
Arrays.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 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5
样例输出
280