📜  门|门CS 2011 |问题 3(1)

📅  最后修改于: 2023-12-03 14:58:37.288000             🧑  作者: Mango

题目介绍

本题目是“门|门”是校内著名的游乐项目。在游玩过程中,游客访问了若干门(有可能是同一个门),最终达到了目的地。现在我们知道游客走过的所有门及目的地,现在我们需要求出至少需要造多少个新门,使得所有游客只要走这些门就可以直达目的地。

本题目的输入是以邻接表形式给出密集图,其中点的个数不超过1000,边数不超过100000。输出至少需造几个门才能满足条件。

解题思路

本题目需要进行网络最大流问题的求解。我们可以将每个门拆成入门和出门两个节点,并在这两个节点之间连一条容量为1的边。同时,在入门节点和出门节点之间也连一条容量为1的边。对于原图中的每一条边(u, v),从出门节点u的出度向入门节点v的入度连一条容量为1的边。对于游客在起点和终点处的门,我们也将其拆成对应的入门和出门节点,并在其对应的入门和出门节点之间连一条容量为1的边。最后,从源点向所有起点的入门节点连一条容量为1的边;从所有终点的出门节点向汇点连一条容量为1的边。利用最大流算法,求解拆分后的网络中,从源点到汇点的最大流即可得到答案。

代码实现

以下是该问题的代码实现,其中 networkFlow 为本题目最大流问题的解法。

from typing import List, Tuple

def min_door_num(edges: List[Tuple[int, int]], s: int, t: int) -> int:
    """求最少需要造多少个新门才能满足条件
    :param edges: 边列表,其中每个元素为两个节点编号,表示一条边
    :param s: 起点编号
    :param t: 终点编号
    :returns: 最少需要造多少个新门
    """
    # 构建最大流网络
    n = max(max(x) for x in edges) + 2
    graph = [[0 for _ in range(n)] for _ in range(n)]
    for u, v in edges:
        u_in, u_out = u * 2, u * 2 + 1
        v_in, v_out = v * 2, v * 2 + 1
        graph[u_out][v_in] += 1
    for i in range(n // 2):
        graph[i*2][i*2+1] += 1
    for i in range(s):
        in_node, out_node = i * 2, i * 2 + 1
        graph[n-2][in_node] += 1
    for i in range(t):
        in_node, out_node = i * 2, i * 2 + 1
        graph[out_node][n-1] += 1
    # 求最大流
    return networkFlow(graph, n-2, n-1)