匈牙利算法的原理为:从当前匹配M(如果没有匹配,则取初始匹配为M=Ø)出发,检查每一个未盖点,然后从它出发寻找可增广路,找到可增广路,则沿着这条可增广路进行扩充,直到不存在可增广路为止。
根据从未盖点出发寻找可增广路搜索的方法,可以分为:
1) DFS增广;
2) BFS增广;
3) 多增广路(Hopcroft-Karp算法)
本文只实现1),2)两种方法
const int MAXN = 11; int nx, ny;//集合X和Y中的顶点最大数 int g[MAXN][MAXN];//g[i][j]表示xi与yj有边相连 int cx[MAXN], cy[MAXN];//cx[i]表示最终求得的最大匹配中与Xi匹配的顶点y,cy[j]同
BFS搜索
int MaxMatch() { int i, j, y; int cur, tail; int res = 0;//所求得的最大的匹配数 memset(cx, 0xff, sizeof(cx));//初始化所有点都是未匹配点 memset(cy, 0xff, sizeof(cy)); for(i = 0; i < nx; ++i) { if(cx[i] != -1) continue; //对X集合中的每个未盖点i进行一次BFS搜索,找交错轨 for(j = 0; j < ny; ++j) pred[j] = -2; cur = tail = 0; for(j = 0; j < ny; ++j)//把顶点i的邻接顶点都入队列 { if(g[i][j]) { pred[j] = -1;//表示i点已经访问过了。 queue[tail++] = j; } } while(cur < tail) { y = queue[cur]; if(cy[y] == -1)//找到一个未盖点,也即是找到一条交错轨 break; cur++; //能走到这一步,说明:y已经匹配给cy[y]了,然后再从cy[y]开始出发,将它的邻接顶点入队列 for(j = 0; j < ny; ++j) { if(pred[j] == -2 && g[ cy[y] ][j]) { pred[j] = y; queue[tail++] = j; } } } if(cur == tail)//你没有找到交错轨 continue; while( pred[y] > -1)//更改交错轨上的匹配状态 { cx[ cy[ pred[y] ] ] = y; cy[y] = cy[ pred[y] ]; y = pred[y]; } cy[y] = i; cx[i] = y; res++;//匹配数加1 } return res; }
DFS搜索
//DFS增广 int visited[MAXN]; //从X集合中的顶点u出发,用深度优先搜索的策略寻找增广路 //这种增广路只能使当前的匹配数加1 int Path( int u ) { for(int j = 0; j < ny; ++j) { if(!visited[j] && g[u][j]) { visited[j] = 1; //如果j没有匹配或者已经匹配了,但是从cy[j]可以找到一条增广轨 //如果前一个条件成立就不会产生递归调用 if(cy[j] == -1 || Path( j )) { cx[u] = j;//把j匹配给u cy[j] = u;//把u匹配给j return 1;//找到了增广路 } } } return 0; } int MaxMatch() { int res = 0; memset(cx, 0xff, sizeof(cx)); memset(cy, 0xff, sizeof(cy)); for(int i = 0; i < nx; ++i) { if(cx[i] == -1) { memset(visited, 0, sizeof(visited)); res += Path( i ); } } return res; }