码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-08-10 21:59:12      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:

 

 

 

 

  网上一堆人写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算法模板

 

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

标签:

原文地址:http://www.cnblogs.com/xcw0754/p/4719177.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!