给定一个源节点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 a和节点dist之间的距离,搜索是否可能有从S到T的流动。
- 如果存在流,则计算距离,值= 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)