二分图之 多重匹配 和 最大权匹配 等总结

 

 

 

一.多重匹配:

HDU3605 Escape (裸题)

POJ2289 Jamie's Contact Groups(二分+多重匹配)

POJ3189 Steady Cow Assignment(二分+多重匹配)

POJ2112 Optimal Milking(二分+多重匹配)

 

 

 

二.最大权匹配及KM算法:

模板:

 1 bool DFS(int x) //找增广路
 2 {
 3     visx[x] = true;
 4     for(int y = 1; y<=ny; y++)
 5     {
 6         if(visy[y]) continue;
 7         int tmp = lx[x] + ly[y] - g[x][y];
 8         if(tmp==0)  //遇到可匹配的,尝试找增广路
 9         {
10             visy[y] = true;
11             if(linker[y]==-1 || DFS(linker[y]))
12             {
13                 linker[y] = x;
14                 return true;
15             }
16         }
17         else    //否则,更新最小期望差值
18             slack[y] = min(slack[y], tmp);
19     }
20     return false;
21 }
22 
23 int KM()
24 {
25     memset(linker, -1, sizeof(linker));
26     memset(ly, 0, sizeof(ly));  //初始化右边标杆
27     for(int i = 1; i<=nx; i++)  //初始化左边标杆
28     {
29         lx[i] = -INF;
30         for(int j = 1; j<=ny; j++)
31             lx[i] = max(lx[i], g[i][j]);
32     }
33 
34     for(int x = 1; x<=nx; x++)     //为左边的每个点找到匹配对象
35     {
36         for(int i = 1; i<=ny; i++)  //初始化最小期望差值
37             slack[i] = INF;
38         while(true)     //多次调整标杆(其实就是多次降低期望值,降低最大权值和),直到找到增广路
39         {
40             memset(visx, 0, sizeof(visx));
41             memset(visy, 0, sizeof(visy));
42 
43             if(DFS(x)) break;   //找增广路,如果找不到,则需要继续降低期望值。
44             int d = INF;
45             for(int i = 1; i<=ny; i++)
46                 if(!visy[i])
47                     d = min(d, slack[i]);
48 
49             for(int i = 1; i<=nx; i++)  //左边访问过的降低期望值,从而可以与未尝试过的点尝试匹配。
50                 if(visx[i])
51                     lx[i] -= d;
52             for(int i = 1; i<=ny; i++)  //右边访问过的提高期望值,以平衡左边减去的那部分。
53             {
54                 if(visy[i]) ly[i] += d;
55                 else slack[i] -= d;
56             }
57         }
58     }
59 
60     int res = 0;
61     for(int i = 1; i<=ny; i++)
62         if(linker[i]!=-1)
63             res += g[linker[i]][i];
64     return res;
65 }
View Code

对KM算法的理解:
假设左边的点为男生, 右边的点为女生。为每个男生都找到女朋友,且好感度之和要最大。
  1.在开始下手之前,每个男生心目中都有一个最喜欢的女生,即好感度最高的。于是,我们就把男生的初始期望值设置为好感度最高的,以表明他们都想得到他们最喜欢的女生。人嘛,一开始都是想要最好的。在这里,初始最大权值和即为所有男生的期望值之和。
  2.现在开始找女朋友了:从左边挑选一个没有找到女朋友的男生开始,逐个女生地挑:
    1)如果不是自己期望值最高的那个女生,那就先不向她示意,而是把她作为保留选择(人都这样),同时,这个男生需要更新一下:如果被最期望值最高的女生拒绝,则最少需要降低多少期望值,才可以继续找女朋友,且是剩下的期望值最高的(人嘛,受挫了就要降低姿态。但是又仍然保留了那份高傲,即使降低姿态也不能降太低)。
    2)如果是自己期望值最高的女生,还等什么,赶紧下手啊!如果女生没有男朋友,或者女生的男朋友可以找到另外一个女生做女朋友(不是自己的永远是最好的)
则成功啦!!然而,如果女生的男朋友找不到另外一个女生做女朋友,那人家肯定不能拱手让爱吧??所以就失败了,那怎么办?女朋友还是要找的,日子还是要过的。所以男生啊,事实哪有想象中的那么美好。所以只能降低一下期值,然后继续找,不言弃,直至成功!!(写代码的时候是访问过的男生都降低最小的期望差值,访问过的女生都增加最少的期望差值,这样左边减少的转移到右边去了,但又因为最大权值和设得过高了,所以左边部分减少的肯定多于右边部分增加的。)

HDU2255 奔小康赚大钱 (裸题)

HDU3488 Tour(深入理解KM算法)

UVA11383 Golden Tiger Claw(KM算法的性质)

Uvalive 4043 Ants(KM算法的利用)

 

 

 

三.婚姻稳定问题 Gale - Shapely算法:

UVALive3989 Ladies' Choice

 

转载于:https://www.cnblogs.com/DOLFAMINGO/p/7852316.html

  • 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、付费专栏及课程。

余额充值