KM算法(二分图的最佳完美匹配)

  网上一堆人写KM算法,还没搜出哪个讲得比较好的。

  KM算法大概过程:

  (1)初始化Lx数组为该boy的一条权值最大的出边。初始化Ly数组为 0。

  (2)对于每个boy,用DFS为其找到一个girl对象,顺路记录下S和T集,并更新每个girl的slack值。若不能为其找到对象,则转3。

  (3)找出非T集合的girl的最小slack值为d,更新S集中的boy和T集中的girl,并且顺路更新非T集中的slack值。对于那个失败的boy继续第2步。

  简括之,就是在保持当前权和最高的情况下,尽量为每个boy找到权更大的边。找的过程就是DFS过程,标记出S和T集是为了保证权和最大,因为只要帮S中任意一个boy另找一个女对象,为这个boy的此次脱单之路告终。

  DFS的要完成的任务:

  (1)标记S和T集。

  (2)更新每个girl的slack值为最小。

  模板还是必须的,带满了注释,改自kuangbin的模板。

  

 1 /* KM算法
 2 * 复杂度O(nx*nx*ny)
 3 * 求最大权匹配(貌似只能求完美匹配?)
 4 * 若求最小权匹配,可将权值取相反数,结果取相反数
 5 * 点的编号从1开始
 6 * 模板以男女模型比较直观。
 7 */
 8 int  nx, ny;                  //两边的点数,x为男,y为女。
 9 int  g[N][N];                 //二分图描述,g[x][y]。
10 int  girl[N], Lx[N], Ly[N];   //girl[i]记录i的匹配成功对象,男女的顶标
11 int  slack[N];      //为了优化用的,连接到对应girl的一条松弛值。
12 bool S[N], T[N];    //匈牙利树的节点集合,S为男,T为女。
13
14 bool DFS(int x) // x一定是个男的
15 {
16     S[x]=true;
17     for(int i=1; i<=ny; i++) //对于每个女的
18     {
19         if(T[i]) continue;
20         int tmp=Lx[x]+Ly[i]-g[x][i];
21         if( tmp==0 )
22         {
23             T[i]=true;
24             if(girl[i]==-1 || DFS(girl[i])) //为第i个girl的男对象另找女对象
25             {
26                 girl[i]=x;      //记录匹配的boy
27                 return true;
28             }
29         }
30         else if(slack[i]>tmp)   //顺便更新下slack
31             slack[i]=tmp;
32     }
33     return false;
34 }
35
36 int KM()
37 {
38     memset(girl, -1, sizeof(girl));
39     memset(Ly, 0, sizeof(Ly));
40
41     for(int i=1; i<=nx; i++) //初始化两个L数组分别为-INF和0
42     {
43         lx[i] = -INF;
44         for(int j=1; j<=ny; j++)
45             if(g[i][j]>lx[i])
46                 lx[i]=g[i][j];
47     }
48
49     for(int j=1; j<=nx; j++)     //对于每个男人
50     {
51         for(int i=1; i<=ny; i++)           //初始时slack为无穷。slack只需要记录女人的。
52             slack[i]=INF;
53
54         while(true)     //无限循环,直到帮其找到对象
55         {
56             memset(S, 0, sizeof(S));
57             memset(T, 0, sizeof(T));
58
59             if( DFS(j) )  break;    //直接就找到对象了,搞定。
60
61             int d=INF;
62             for(int i=1; i<=ny; i++)       //根据不在匈牙利树上的女人的slack找到最小值d
63                 if(!T[i] && d>slack[i])
64                     d=slack[i];
65
66             for(int i=1; i<=nx; i++)     //所有匈牙利树上的男人更新lx值
67                 if(S[i])
68                     Lx[i]-=d;
69
70             for(int i=1; i<=ny; i++)     //树上的女人加d,不在树上的女人的slack减d。
71             {
72                 if(T[i])     Ly[i]+=d;      //这是为了让等式仍然成立
73                 else         slack[i]-=d;   //为何要做这一步?
74             }
75         }
76     }
77     int ans=0;
78     for(int i=1; i<=ny; i++)       //累计匹配边的权和
79         if(girl[i]>0)
80             ans+=g[girl[i]][i];
81     return ans;
82 }

KM算法模板

时间: 2024-10-12 17:38:20

KM算法(二分图的最佳完美匹配)的相关文章

hdu1533 Going Home km算法解决最小权完美匹配

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5539    Accepted Submission(s): 2907 Problem Description On a grid map there are n little men and n houses. In each unit time, every l

poj3565 Ants km算法求最小权完美匹配,浮点权值

/** 题目:poj3565 Ants km算法求最小权完美匹配,浮点权值. 链接:http://poj.org/problem?id=3565 题意:给定n个白点的二维坐标,n个黑点的二维坐标. 求是否存在n条边,每条边恰好连一个白点,一个黑点,且所有的边不相交. 输出所有黑点连接的白点编号. 思路:最小权完美匹配. 假定有白点1(a1,b1), 2(a2,b2), 黑点3(a3,b3),4(a4,b4); 如果1(a1,b1)与3(a3,b3)相连,2(a2,b2)与4(a4,b4)相连,如

HDU_2255 二分图最佳完美匹配 KM匈牙利算法

一开始还没看懂这个算法,后来看了陶叔去年的PPT的实例演示才弄懂 用一个lx[]和ly[]来记录X和Y集合中点的权值,有个定理是 lx[i]+ly[j]==w[i][j](边权值) 则该点是最佳匹配,因为首先 那个不等式肯定要>=的,否则就不满足题意了,如果是>则可以去匹配更有价值的边或者把权值降下来让匹配边的潜力更大. 所以只有把握了这个条件,其他就是走一遍最大匹配数.以及up()函数用来在无法匹配的时候,进行其他点的权值降低(也可以说是增广路的搜索)来得到匹配. #include <

【二分图最大权完美匹配】【KM算法模板】【转】

[文章详解出处]https://www.cnblogs.com/wenruo/p/5264235.html KM算法是用来求二分图最大权完美匹配的.[也就算之前的匈牙利算法求二分最大匹配的变种??] 这里就贴一下模板代码..2333... 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6

UVa 11383 少林决胜(二分图最佳完美匹配)

https://vjudge.net/problem/UVA-11383 题意: 给定一个N×N矩阵,每个格子里都有一个正整数W(i,j).你的任务是给每行确定一个整数row(i),每列也确定一个整数col(i),使得对于任意格子(i,j),w(i,j)<=row(i)+col(j).所有的row(i)和col(i)只和应尽量小. 思路: 利用二分图最佳完美匹配当中的l(x)+l(y)>=w(i,j),直接用KM算法即可. 1 #include<iostream> 2 #inclu

UVA - 1045 The Great Wall Game(二分图最佳完美匹配)

题目大意:给出棋盘上的N个点的位置.如今问将这些点排成一行或者一列.或者对角线的最小移动步数(每一个点都仅仅能上下左右移动.一次移动一个) 解题思路:暴力+二分图最佳完美匹配 #include <cstdio> #include <cstring> #define N 20 #define INF 0x3f3f3f3f #define abs(x) ((x) > 0 ? (x) : (-(x))) #define max(a,b)((a)>(b)? (a):(b)) #

UVALive 4043 转化最佳完美匹配

首先黑点和白点是组成一个二分图这毫无疑问 关键是题目中要求的所有黑白配的线不能交叉...一开始我也没想到这个怎么转化为二分图里面的算法. 后来看书才知道,如果两两交叉,则可以把两根线当四边形的对角线,连四边形的两条边,则肯定不交叉,而且一个很明显的特征是,不交叉的两条线的他们的长度和 一定比交叉线的长度和小. 于是我们只要求出最小长度的线,就必定是不相交的.那就要用到最佳完美匹配了,首先算出两两点的欧几里得距离,然后取负数,这样走一遍匹配,得到的必定是最短的欧几里得距离,即不相交的线 #incl

UVaLive 4043 Ants (最佳完美匹配)

题意:给定 n 个只蚂蚁和 n 棵树的坐标,问怎么匹配使得每个蚂蚁到树的连线不相交. 析:可以把蚂蚁和树分别看成是两类,那么就是一个完全匹配就好,但是要他们的连线不相交,那么就得考虑,最佳完美匹配是可以的,为什么呢,假设有两条线段a1-b1和a2-b2,那么如果相交,dist(a1, b1) + dist(a2, b2) > dist(a1, b2) + dist(a2, b1),自己画图看看就好,然后如果是最小的距离,那么就是可以的了,只要在用使得KM匹配时,把权值取反就好. 代码如下: #p

UVa 1349 (二分图最小权完美匹配) Optimal Bus Route Design

题意: 给出一个有向带权图,找到若干个圈,使得每个点恰好属于一个圈.而且这些圈所有边的权值之和最小. 分析: 每个点恰好属于一个有向圈 就等价于 每个点都有唯一后继. 所以把每个点i拆成两个点,Xi 和 Yi ,然后求二分图最小权完美匹配(流量为n也就是满载时,就是完美匹配). 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 200 + 10; 6 const int INF = 10000000