一直没有学习匈牙利算法,因为网络流实现匹配的功能已经足够强大了。
但今天这道题【BZOJ1191】用网络流实在难以解决动态匹配,而鉴于匈牙利算法实现的代码复杂度极小,所以今天学习一下。
匈牙利算法用于解决二分图匹配问题,主要思想是增广路,对于当前左点u,若能找到一个相连的未匹配的右点v,则直接匹配,否则进行尝试更改其他已匹配的右点匹配的左点的匹配对象【递归】,若成功则匹配成功
二分图匹配问题还有很多变式:
最小点覆盖集 = 最大点独立集 = 最大匹配
最小路径覆盖数 = 点数 - 最大匹配
上题:
BZOJ1191
大意:二分图匹配= =
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long int #define REP(i,n) for (int i = 1; i <= (n); i++) #define fo(i,x,y) for (int i = (x); i <= (y); i++) #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next) using namespace std; const int maxn = 1005,maxm = 100005,INF = 1000000000; inline int read(){ int out = 0,flag = 1;char c = getchar(); while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();} return out * flag; } int n,m,lk[maxn],vis[maxn]; int head[maxn],nedge = 0; struct EDGE{int to,next;}edge[maxm]; inline void build(int u,int v){ edge[nedge] = (EDGE){v,head[u]}; head[u] = nedge++; } bool find(int u){ int to; Redge(u) if (!vis[to = edge[k].to]){ vis[to] = true; if (!lk[to] || find(lk[to])){ lk[to] = u; return true; } } return false; } int main() { fill(head,head + maxn,-1); int ans = 0; n = read(); m = read(); REP(i,m) build(i,read()),build(i,read()); REP(i,m){ memset(vis,0,sizeof(vis)); if (find(i)) ans++; else break; } cout<<ans<<endl; return 0; }