Costo mínimo Flujo máximo de un gráfico usando el algoritmo Bellman Ford

Dado un Node fuente S, un Node sumidero T , dos arrays Cap[ ][ ] y Cost[ ][ ] que representan un gráfico, donde Cap[i][j] es la capacidad de un borde dirigido desde el Node i al Node j y cost[i][j] es el costo de enviar una unidad de flujo a lo largo de un borde dirigido desde el Node i al Node j , la tarea es encontrar un flujo con el flujo máximo de costo mínimo posible del gráfico dado.

Costo mínimo Flujo máximo: Costo mínimo (por unidad de flujo) requerido para entregar la máxima cantidad de flujo posible del gráfico dado. 
 

Ejemplo:

Entrada: 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}}, 
costo[ ][ ] = {{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}} 
Salida: 10 1 
Explicación : 
Para el gráfico dado, Max flow = 10 y Min cost = 1.

Entrada: S = 0, T = 4, costo[][] = { { 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 } } 
Salida: 6 8 
 

Enfoque:
el ciclo negativo en la red de costos se cicla con la suma de los costos de todos los bordes en el ciclo es negativa. Se pueden detectar utilizando el algoritmo de Bellman Ford . Deben eliminarse porque, en la práctica, no se puede permitir el flujo a través de tales ciclos. Considere un ciclo de costo negativo , si todo el flujo tiene que pasar por este ciclo, el costo total siempre se reduce por cada ciclo completado. Esto daría como resultado un bucle infinito en el deseo de minimizar el costo total . Entonces, cada vez que una red de costos incluye un ciclo negativo, implica que el costo puede minimizarse aún más (fluyendo a través del otro lado del ciclo en lugar del lado actualmente considerado). Un ciclo negativo una vez detectado se elimina haciendo fluir unCapacidad de cuello de botella en todas las aristas del ciclo.

Ahora, mira qué son los Nodes de oferta y demanda: 

Nodes de suministro: Son Nodes positivos que se suman al flujo y que producen el flujo.
Nodes de demanda: Son Nodes negativos que se restan del flujo.
Oferta (o demanda) en cada Node = Flujo total que sale del Node – El flujo total que entra al Node 
 

El problema dado se aborda mediante el envío de una capacidad de cuello de botella a todos los bordes del ciclo para encargarse del ciclo negativo. Además, dado que involucra Nodes de demanda, se invoca  el algoritmo Bellman Ford .

Siga los pasos a continuación para resolver el problema: 

  • Almacene la capacidad de un borde y el costo de ese borde en dos arreglos separados.
  • Dado el Node de origen S y el Node receptor T , el borde seleccionado p i , los Nodes de demanda d a y la distancia entre los Nodes dist , busque si es posible tener un flujo de S a T .
  • Si existe un flujo, calcule la distancia, value = dist + pi – pi[k] – cost[k] .
  • Compare los valores de distancia en dist[ ] con value y siga actualizando hasta obtener el flujo mínimo .

A continuación se muestra la implementación del enfoque anterior:

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 until 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 until 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
Producción: 

6 8

 

Complejidad temporal: O(V 2 * E 2 ) donde V es el número de vértices y E es el número de aristas.  
Espacio Auxiliar: O(V)
 

Publicación traducida automáticamente

Artículo escrito por iancarson y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *