标签:
网上一堆人写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 }
标签:
原文地址:http://www.cnblogs.com/xcw0754/p/4719177.html