二分图匹配之匈牙利算法
二分图匹配的问题都可以用网络流来做,但是二分图匹配的一些思想还是得了解一下。
匈牙利算法:
我们将左边集合记为S,右边集合记为T,
加边的时候只需要加S---->T的边,∞后面会提到原因。
我们枚举点进行增广,增广的时候只访问当次增广没有访问到的点。
什么情况下才算是成功的增广?
u---->v的v点没有匹配过,或者当前匹配v的点还能找到一个点去匹配,
这样u就与v匹配。并且每次枚举点,就要清空vis数组,因为我们不希望
在一次增广中重复访问访问过的结点。
∞reason:每一次成功的增广都只需要从S集合中在T集合中找匹配,
继续用记录v有没有被匹配,每次都会从u去找匹配。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<map> #define ll long long int using namespace std; const int N=1e6+5; int n,m,ee,num=1,ans; int cx[N],cy[N],vis[N],head[N]; struct E{ int nxt,to; }e[N]; void add(int u,int v){ e[++num].to=v; e[num].nxt=head[u]; head[u]=num; } int dfs(int u){ for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(!vis[v]){ vis[v]=1; if((!cy[v])||(dfs(cy[v]))){ cy[v]=u; return 1; } } } return 0; } void max_match(){ for(int u=1;u<=n;u++){ memset(vis,0,sizeof(vis)); ans+=dfs(u); } } int main(){ scanf("%d%d%d",&n,&m,&ee); for(int i=1;i<=ee;i++){ int u,v; scanf("%d%d",&u,&v); if(u<=n&&v<=m) add(u,v); } max_match(); printf("%d",ans); return 0; }