匈牙利算法基本思想:找到满足以下条件的路径
- 起点和终点是未纳入已分配边的顶点,且两个顶点在不同的两个划分
- 这条路径的奇数边是未纳入分配的边,而偶数边是已近被分配的边。
- 根据1和二分图的性质,路径经过边的数目一定是奇数
于是:未纳入匹配的边刚好比已经纳入匹配的边多一个。如果把这样的路径取反(奇数边->纳入匹配,偶数边从原匹配集合中删除),则总的匹配数+1
反复查找直到没有这样的路径为止,则最后的结果就是二分图的最大匹配数。
- POJ_1274
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 205;
int n, m;
bool path[MAXN][MAXN];
int front[MAXN];
int ans;
bool visit[MAXN];
bool dfs(int start)
{
for(int i=1; i<=m; i++)
{
if(path[start][i] && !visit[i])
{
visit[i] = true;
if(front[i]==0 || dfs(front[i]))
{
front[i] = start;
return true;
}
}
}
return false;
}
int main()
{
while(scanf("%d%d", &n, &m) == 2)
{
memset(path, 0, sizeof(path));
memset(front, 0, sizeof(front));
int i, t, des;
for(i=1; i<=n; i++)
{
scanf("%d", &t);
while(t--)
{
scanf("%d", &des);
path[i][des] = true;
}
}
/* 每次从二分图的一个划分 A 中取一点 p(p肯定是还没有被纳入匹配边的点),然后找到可达的另外一个划分 B 中的一点 q,
*
* 如果 p, q 都没有被纳入匹配的边中,则将edge[p, q]纳入匹配,总匹配 +1;
*
* 如果 q 已经是属于匹配过的边 e 的一个顶点,则找到边 e 的另一个顶点 r(该点必在 A 划分中)
* 如果 r 有一条边与 B 划分中的某一个顶点 s 相连,且边 edge[r,s] 没有纳入匹配的边,
* 则就找到一条增广路径:edge[p,q], edge[q,r], edge[r,s] 满足:
* 1.起点和终点是未纳入已分配边的顶点,且两个顶点在不同的两个划分
* 2.这条路径的奇数边是未纳入分配的边edge[p,q], edge[r,s],而偶数边是已近被分配的边edge[q,r]
* 3.路径所经过边的数目是奇数
* 对路径取反,则总匹配数 +1
*/
ans = 0;
for(i=1; i<=n; i++)
{
memset(visit, 0, sizeof(visit));
if(dfs(i))
ans ++;
}
printf("%d\n", ans);
}
return 0;
}