博客分享
大佬的博客,有趣易懂:
算法讲解:二分图匹配
二分图匹配——匈牙利算法
基本概念
无向图
边没有方向的图。
二分图
设G=(V,E)
是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)
所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B)
,则称图G为一个二分图。
匹配
给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
极大匹配(Maximal Matching) 是指在当前已完成的匹配下,无法再通过增加未完成匹配的边的方式来增加匹配的边数。
最大匹配(maximum matching) 是所有极大匹配当中边数最大的一个匹配。选择这样的边数最大的子集称为图的最大匹配问题。
如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配。
匈牙利算法
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int k, m, n;
int G[510][510];
int match[510], boy[510]; //match储存匹配结果、boy相当于vis作为标记数组
bool dfs(int x){ //找一个增广路径
for (int i = 1; i <= n; i++)
if(!boy[i] && G[x][i]){
boy[i] = 1; //预定男孩i,准备分给女孩x
if(!match[i] || dfs(match[i])){
//(1)如果男孩i还没配对,就分给女孩x
//(2)如果男孩i已经配对,尝试用dfs()更换原配女孩,以腾出位置给女孩x
match[i] = x; //匹配成功(如果原来有配对,更换成功)现在男孩i属于女孩x
return true;
}
}
return false; //女孩没有喜欢的男孩,或更换不成功
}
int main(){
while(cin>> k){
if(!k) break;
cin >> m >> n;
memset(G, 0, sizeof G);
memset(match, 0, sizeof match);
for (int i = 0; i < k; i++){
int a, b;
cin >> a >> b;
G[a][b] = 1;
}
int sum = 0;
for (int i = 1; i <= m; i++){
memset(boy, 0, sizeof boy);
if(dfs(i))
sum++;
}
cout << sum << endl;
}
return 0;
}