匈牙利算法的原理为:从当前匹配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;
}