给定一个源节点S,一个汇节点T ,两个矩阵Cap[ ][ ]和Cost[ ][ ]表示一个图,其中Cap[i][j]是从节点i到节点j的有向边的容量和cost[i][j]是沿着从节点i到节点j 的有向边发送一个单位流的成本,任务是从给定的图中找到一个具有最小成本最大流量的流。
Minimum Cost Maximum Flow: Minimum cost(per unit of flow) required to deliver maximum amount of flow possible from the given graph.
例子:
Input: S = 0, T = 4, cap[ ][ ] = {{0, 3, 4, 5, 0}, {0, 0, 2, 0, 0}, {0, 0, 0, 4, 1}, {0, 0, 0, 0, 10}, {0, 0, 0, 0, 0}},
cost[ ][ ] = {{0, 1, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}
Output: 10 1
Explanation:
For given graph, Max flow = 10 and Min cost = 1.
Input: S = 0, T = 4, cost[][] = { { 0, 1, 0, 0, 2 }, { 0, 0, 0, 3, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0 } }
cap[][] = { { 0, 3, 1, 0, 3 }, { 0, 0, 2, 0, 0 }, { 0, 0, 0, 1, 6 }, { 0, 0, 0, 0, 2 }, { 0, 0, 0, 0, 0 } }
Output: 6 8
方法:
成本网络中的负循环循环,循环中所有边的成本总和为负。可以使用 Bellman Ford 算法检测它们。它们应该被消除,因为实际上不允许流过这样的循环。考虑一个负成本循环,如果所有流都必须通过这个循环,那么每完成一个循环,总成本总是在减少。这将导致在最小化总成本的愿望中的无限循环。因此,每当成本网络包含负循环时,这意味着可以进一步最小化成本(通过流经循环的另一侧而不是当前考虑的一侧)。通过使瓶颈容量流过循环中的所有边缘来消除一旦检测到的负循环。
现在,看看什么是供需节点:
Supply nodes: These are positive Nodes that are added to the flow and which produces the flow.
Demand nodes: These are negative nodes which are subtracted from the flow.
Supply (or demand) at each node = Total flow leading out of the Node – The total flow leading into the Node
通过向循环中的所有边发送瓶颈容量来处理负循环来解决给定的问题。此外,由于它涉及需求节点,因此调用了 Bellman Ford 算法。
请按照以下步骤解决问题:
- 将边的容量和该边的成本存储在两个单独的数组中。
- 鉴于源节点S和宿节点T,拾取边缘P I,需求节点d和节点距离DIST之间,搜索是否有可能以具有选自S流至T。
- 如果存在流,则计算距离, value = dist + pi – pi[k] – cost[k] 。
- 将dist[ ] 中的距离值与value 进行比较并不断更新,直到获得最小流量。
下面是上述方法的实现:
Java
// Java Program to implement
// the above approach
import java.util.*;
public class MinCostMaxFlow {
// Stores the found edges
boolean found[];
// Stores the number of nodes
int N;
// Stores the capacity
// of each edge
int cap[][];
int flow[][];
// Stores the cost per
// unit flow of each edge
int cost[][];
// Stores the distance from each node
// and picked edges for each node
int dad[], dist[], pi[];
static final int INF
= Integer.MAX_VALUE / 2 - 1;
// Function to check if it is possible to
// have a flow from the src to sink
boolean search(int src, int sink)
{
// Initialise found[] to false
Arrays.fill(found, false);
// Initialise the dist[] to INF
Arrays.fill(dist, INF);
// Distance from the source node
dist[src] = 0;
// Iterate untill src reaches N
while (src != N) {
int best = N;
found[src] = true;
for (int k = 0; k < N; k++) {
// If already found
if (found[k])
continue;
// Evaluate while flow
// is still in supply
if (flow[k][src] != 0) {
// Obtain the total value
int val
= dist[src] + pi[src]
- pi[k] - cost[k][src];
// If dist[k] is > minimum value
if (dist[k] > val) {
// Update
dist[k] = val;
dad[k] = src;
}
}
if (flow[src][k] < cap[src][k]) {
int val = dist[src] + pi[src]
- pi[k] + cost[src][k];
// If dist[k] is > minimum value
if (dist[k] > val) {
// Update
dist[k] = val;
dad[k] = src;
}
}
if (dist[k] < dist[best])
best = k;
}
// Update src to best for
// next iteration
src = best;
}
for (int k = 0; k < N; k++)
pi[k]
= Math.min(pi[k] + dist[k],
INF);
// Return the value obtained at sink
return found[sink];
}
// Function to obtain the maximum Flow
int[] getMaxFlow(int cap[][], int cost[][],
int src, int sink)
{
this.cap = cap;
this.cost = cost;
N = cap.length;
found = new boolean[N];
flow = new int[N][N];
dist = new int[N + 1];
dad = new int[N];
pi = new int[N];
int totflow = 0, totcost = 0;
// If a path exist from src to sink
while (search(src, sink)) {
// Set the default amount
int amt = INF;
for (int x = sink; x != src; x = dad[x])
amt = Math.min(amt,
flow[x][dad[x]] != 0
? flow[x][dad[x]]
: cap[dad[x]][x]
- flow[dad[x]][x]);
for (int x = sink; x != src; x = dad[x]) {
if (flow[x][dad[x]] != 0) {
flow[x][dad[x]] -= amt;
totcost -= amt * cost[x][dad[x]];
}
else {
flow[dad[x]][x] += amt;
totcost += amt * cost[dad[x]][x];
}
}
totflow += amt;
}
// Return pair total cost and sink
return new int[] { totflow, totcost };
}
// Driver Code
public static void main(String args[])
{
// Creating an object flow
MinCostMaxFlow flow = new MinCostMaxFlow();
int s = 0, t = 4;
int cap[][] = { { 0, 3, 1, 0, 3 },
{ 0, 0, 2, 0, 0 },
{ 0, 0, 0, 1, 6 },
{ 0, 0, 0, 0, 2 },
{ 0, 0, 0, 0, 0 } };
int cost[][] = { { 0, 1, 0, 0, 2 },
{ 0, 0, 0, 3, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1 },
{ 0, 0, 0, 0, 0 } };
int ret[] = flow.getMaxFlow(cap, cost, s, t);
System.out.println(ret[0] + " " + ret[1]);
}
}
Python3
# Python3 program to implement
# the above approach
from sys import maxsize
from typing import List
# Stores the found edges
found = []
# Stores the number of nodes
N = 0
# Stores the capacity
# of each edge
cap = []
flow = []
# Stores the cost per
# unit flow of each edge
cost = []
# Stores the distance from each node
# and picked edges for each node
dad = []
dist = []
pi = []
INF = maxsize // 2 - 1
# Function to check if it is possible to
# have a flow from the src to sink
def search(src: int, sink: int) -> bool:
# Initialise found[] to false
found = [False for _ in range(N)]
# Initialise the dist[] to INF
dist = [INF for _ in range(N + 1)]
# Distance from the source node
dist[src] = 0
# Iterate untill src reaches N
while (src != N):
best = N
found[src] = True
for k in range(N):
# If already found
if (found[k]):
continue
# Evaluate while flow
# is still in supply
if (flow[k][src] != 0):
# Obtain the total value
val = (dist[src] + pi[src] -
pi[k] - cost[k][src])
# If dist[k] is > minimum value
if (dist[k] > val):
# Update
dist[k] = val
dad[k] = src
if (flow[src][k] < cap[src][k]):
val = (dist[src] + pi[src] -
pi[k] + cost[src][k])
# If dist[k] is > minimum value
if (dist[k] > val):
# Update
dist[k] = val
dad[k] = src
if (dist[k] < dist[best]):
best = k
# Update src to best for
# next iteration
src = best
for k in range(N):
pi[k] = min(pi[k] + dist[k], INF)
# Return the value obtained at sink
return found[sink]
# Function to obtain the maximum Flow
def getMaxFlow(capi: List[List[int]],
costi: List[List[int]],
src: int, sink: int) -> List[int]:
global cap, cost, found, dist, pi, N, flow, dad
cap = capi
cost = costi
N = len(capi)
found = [False for _ in range(N)]
flow = [[0 for _ in range(N)]
for _ in range(N)]
dist = [INF for _ in range(N + 1)]
dad = [0 for _ in range(N)]
pi = [0 for _ in range(N)]
totflow = 0
totcost = 0
# If a path exist from src to sink
while (search(src, sink)):
# Set the default amount
amt = INF
x = sink
while x != src:
amt = min(
amt, flow[x][dad[x]] if
(flow[x][dad[x]] != 0) else
cap[dad[x]][x] - flow[dad[x]][x])
x = dad[x]
x = sink
while x != src:
if (flow[x][dad[x]] != 0):
flow[x][dad[x]] -= amt
totcost -= amt * cost[x][dad[x]]
else:
flow[dad[x]][x] += amt
totcost += amt * cost[dad[x]][x]
x = dad[x]
totflow += amt
# Return pair total cost and sink
return [totflow, totcost]
# Driver Code
if __name__ == "__main__":
s = 0
t = 4
cap = [ [ 0, 3, 1, 0, 3 ],
[ 0, 0, 2, 0, 0 ],
[ 0, 0, 0, 1, 6 ],
[ 0, 0, 0, 0, 2 ],
[ 0, 0, 0, 0, 0 ] ]
cost = [ [ 0, 1, 0, 0, 2 ],
[ 0, 0, 0, 3, 0 ],
[ 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 1 ],
[ 0, 0, 0, 0, 0 ] ]
ret = getMaxFlow(cap, cost, s, t)
print("{} {}".format(ret[0], ret[1]))
# This code is contributed by sanjeev2552
6 8
时间复杂度: O(V 2 * E 2 ) 其中 V 是顶点数,E 是边数。
辅助空间: O(V)
如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live