# minimum cost maximum flow from a graph using bellman ford algorithm | python3 program to implement the above approach ; stores the found edges ; stores the number of nodes ; stores the capacity of each edge ; stores the cost per unit flow of each edge ; stores the distance from each node and picked edges for each node ; function to check if it is possible to have a flow from the src to sink ; initialise found [ ] to false ; initialise the dist [ ] to inf ; distance from the source node ; iterate untill src reaches n ; if already found ; evaluate while flow is still in supply ; obtain the total value ; if dist [ k ] is > minimum value ; update ; if dist [ k ] is > minimum value ; update ; update src to best for next iteration ; return the value obtained at sink ; function to obtain the maximum flow ; if a path exist from src to sink ; set the default amount ; return pair total cost and sink ; 

from sys import maxsize
from typing import List
found = []
N = 0
cap = []
flow = []
cost = []
dad = []
dist = []
pi = []
INF = maxsize // 2 - 1


def search(src: int, sink: int) -> bool:
    found = [False for _ in range(N)]
    dist = [INF for _ in range(N + 1)]
    dist[src] = 0
    while (src != N):
        best = N
        found[src] = True
        for k in range(N):
            if (found[k]):
                continue
            if (flow[k][src] != 0):
                val = (dist[src] + pi[src] - pi[k] - cost[k][src])
                if (dist[k] > val):
                    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] > val):
                    dist[k] = val
                    dad[k] = src
            if (dist[k] < dist[best]):
                best = k
        src = best
    for k in range(N):
        pi[k] = min(pi[k] + dist[k], INF)
    return found[sink]


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
    while (search(src, sink)):
        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 [totflow, totcost]


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]))

# Expected output:
6 8