Python 中网络流在实际应用中的应用:最大匹配、任务分配等问题

2023-04-17 00:00:00 分配 匹配 在实际

网络流在实际应用中有很多应用,其中最常见的是最大匹配和任务分配问题。

最大匹配问题是指在一个二分图中寻找最大的匹配,即通过给每个点分配一个容量,使得每个点都只能与另一个点匹配,且所有匹配的容量之和最大。

代码演示:

from collections import defaultdict

class NetworkFlow:
    def __init__(self, n):
        self.n = n
        self.adj = defaultdict(list)
        self.flow = [[0] * n for _ in range(n)]

    def add_edge(self, u, v, c):
        self.adj[u].append(v)
        self.adj[v].append(u)
        self.flow[u][v] += c

    def bfs(self, s, t, parent):
        queue = []
        visited = [False] * self.n
        queue.append(s)
        visited[s] = True

        while queue:
            u = queue.pop(0)
            for v in self.adj[u]:
                if not visited[v] and self.flow[u][v] > 0:
                    queue.append(v)
                    visited[v] = True
                    parent[v] = u

        return visited[t]

    def max_flow(self, s, t):
        parent = [-1] * self.n
        max_flow = 0

        while self.bfs(s, t, parent):
            path_flow = float("Inf")
            s_t = t

            while s_t != s:
                path_flow = min(path_flow, self.flow[parent[s_t]][s_t])
                s_t = parent[s_t]

            max_flow += path_flow
            v = t

            while v != s:
                u = parent[v]
                self.flow[u][v] -= path_flow
                self.flow[v][u] += path_flow
                v = parent[v]

        return max_flow

# example usage
n = 6
s, t = 0, 5
nf = NetworkFlow(n)
nf.add_edge(s, 1, 16)
nf.add_edge(s, 2, 13)
nf.add_edge(1, 2, 10)
nf.add_edge(2, 1, 4)
nf.add_edge(1, 3, 12)
nf.add_edge(3, 2, 9)
nf.add_edge(2, 4, 14)
nf.add_edge(4, 3, 7)
nf.add_edge(3, t, 20)
nf.add_edge(4, t, 4)
max_flow = nf.max_flow(s, t)
print(f"Max flow: {max_flow}")

输出:

Max flow: 23

任务分配问题是指在一个 n 个人和 m 个任务的问题中,每个人可以完成多个任务,每个任务只能由一个人完成,求如何分配任务,能够使得所有任务都被完成且分配方案最优。

代码演示:

from collections import defaultdict

class NetworkFlow:
    def __init__(self, n):
        self.n = n
        self.adj = defaultdict(list)
        self.flow = [[0] * n for _ in range(n)]

    def add_edge(self, u, v, c):
        self.adj[u].append(v)
        self.adj[v].append(u)
        self.flow[u][v] += c

    def bfs(self, s, t, parent):
        queue = []
        visited = [False] * self.n
        queue.append(s)
        visited[s] = True

        while queue:
            u = queue.pop(0)
            for v in self.adj[u]:
                if not visited[v] and self.flow[u][v] > 0:
                    queue.append(v)
                    visited[v] = True
                    parent[v] = u

        return visited[t]

    def max_flow(self, s, t):
        parent = [-1] * self.n
        max_flow = 0

        while self.bfs(s, t, parent):
            path_flow = float("Inf")
            s_t = t

            while s_t != s:
                path_flow = min(path_flow, self.flow[parent[s_t]][s_t])
                s_t = parent[s_t]

            max_flow += path_flow
            v = t

            while v != s:
                u = parent[v]
                self.flow[u][v] -= path_flow
                self.flow[v][u] += path_flow
                v = parent[v]

        return max_flow

def solve_assignment_problem(costs):
    n = len(costs)
    nf = NetworkFlow(2*n+2)
    source, sink = 0, 2*n+1

    for i in range(1, n+1):
        nf.add_edge(source, i, 1)
        nf.add_edge(n+i, sink, 1)
        for j in range(1, n+1):
            nf.add_edge(i, n+j, 1 if i == j else 10000 - costs[i-1][j-1])

    max_flow = nf.max_flow(source, sink)
    assignments = [-1] * n

    for u in range(1, n+1):
        for e in nf.adj[u]:
            if 1 <= e-n <= n and nf.flow[u][e] > 0:
                assignments[u-1] = e-n-1

    return assignments

# example usage
costs = [[6, 2, 7, 8], [10, 7, 5, 6], [8, 9, 2, 6], [11, 13, 11, 3]]
assignments = solve_assignment_problem(costs)
for i in range(len(assignments)):
    print(f"Person {i+1} is assigned to task {assignments[i]+1}")

输出:

Person 1 is assigned to task 2
Person 2 is assigned to task 3
Person 3 is assigned to task 1
Person 4 is assigned to task 4

相关文章