二分图多重匹配问题

在二分图最大匹配中,每个点(不管是X方点还是Y方点)最多只能和一条匹配边相关联,然而,我们经常遇到这种问题,即二分图匹配中一个点可以和多条匹配边相关联,但有上限,或者说,Li表示点i最多可以和多少条匹配边相关联。

二分图多重匹配分为二分图多重最大匹配与二分图多重最优匹配两种,分别可以用最大流与最大费用最大流解决。

(1)二分图多重最大匹配:
在原图上建立源点S和汇点T,S向每个X方点连一条容量为该X方点L值的边,每个Y方点向T连一条容量为该Y方点L值的边,原来二分图中各边在新的网络中仍存在,容量为1(若该边可以使用多次则容量大于1),求该网络的最大流,就是该二分图多重最大匹配的值。

(2)二分图多重最优匹配:
在原图上建立源点S和汇点T,S向每个X方点连一条容量为该X方点L值、费用为0的边,每个Y方点向T连一条容量为该Y方点L值、费用为0的边,原来二分图中各边在新的网络中仍存在,容量为1(若该边可以使用多次则容量大于1),费用为该边的权值。求该网络的最大费用最大流,就是该二分图多重最优匹配的值。

例题:
【1】POJ1698 Alice's Chance
将电影作为X方点,每一天作为Y方点(最多50周,每周7天,所以共设350个Y方点),若第i个电影可以在第j天搞就连边(i, j)。每个X方点的L值为该电影总共要搞多少天,每个Y方点的L值为1(每天最多只能搞一个电影),然后求二分图多重最大匹配,若能使所有从源点连向X方点的边都满流,则输出Yes,否则输出No。
【2】POJ2112 Optimal Milking
先预处理求出每两个点(包括挤奶点和牛)间的最短距离,然后将所有挤奶点作为X方点(L值为该挤奶点最多可以容纳多少牛),所有牛作为Y方点(L值为1),Xi和Yj间边的权值为这两个点之间的最短距离(若这两点间不存在路径则此处无边),然后问题就变成了求一个多重匹配,使得每个Y方点都有匹配点且匹配边中权值的最大值最小。
可以枚举最大边权值S,然后,原图中所有权值大于S的边都要删去。若此时图中存在符合要求的多重匹配,则S合法否则S不合法。由于S的合法性是单调的,所以可以二分枚举S。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用networkx库实现二分图多重匹配的Python代码示例: ```python import networkx as nx def bipartite_max_matching(bipartite_graph): """ 二分图多重匹配 :param bipartite_graph: 二分图,使用networkx库的Graph对象表示 :return: 匹配结果,为一个Python字典,左侧节点为键,值为匹配的右侧节点列表 """ # 将二分图转化为网络流 flow_graph = nx.DiGraph() # 添加源点和汇点 flow_graph.add_node("source") flow_graph.add_node("sink") # 添加左侧节点 for left_node in bipartite_graph.left: # 添加入点和出点 in_node = "in_" + left_node out_node = "out_" + left_node flow_graph.add_node(in_node) flow_graph.add_node(out_node) # 将入点向出点连一条容量为1的边 flow_graph.add_edge(in_node, out_node, capacity=1) # 将源点向入点连一条容量为1的边 flow_graph.add_edge("source", in_node, capacity=1) # 将左侧节点的出点向右侧节点的入点连一条容量为1的边 for right_node in bipartite_graph.right: if bipartite_graph.has_edge(left_node, right_node): flow_graph.add_edge(out_node, "in_" + right_node, capacity=1) # 添加右侧节点 for right_node in bipartite_graph.right: # 添加入点和出点 in_node = "in_" + right_node out_node = "out_" + right_node flow_graph.add_node(in_node) flow_graph.add_node(out_node) # 将入点向出点连一条容量为1的边 flow_graph.add_edge(in_node, out_node, capacity=1) # 将右侧节点的出点向汇点连一条容量为1的边 flow_graph.add_edge(out_node, "sink", capacity=1) # 计算最大流 max_flow_value, max_flow_dict = nx.maximum_flow(flow_graph, "source", "sink") # 提取匹配结果 matching = {} for left_node in bipartite_graph.left: matching[left_node] = [] for right_node in bipartite_graph.right: if "out_" + left_node in max_flow_dict and \ "in_" + right_node in max_flow_dict["out_" + left_node]: if max_flow_dict["out_" + left_node]["in_" + right_node] > 0: matching[left_node].append(right_node) return matching ``` 需要注意的是,以上代码假设二分图的左侧节点为`bipartite_graph.left`,右侧节点为`bipartite_graph.right`,边集为`bipartite_graph.edges`。其中,`bipartite_graph.edges`为一个Python列表,每个元素为形如`(left_node, right_node)`的元组,表示左侧节点`left_node`和右侧节点`right_node`之间有一条边。在这个假设下,`bipartite_graph.has_edge(left_node, right_node)`可以用来判断是否存在从左侧节点`left_node`到右侧节点`right_node`的边。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值