二分图匹配
之前写过二分图匹配的博客,但就是感觉看了那篇博客也无法真正懂得二分图匹配,所以就再写一篇了。
先普及一下概念:
二分图:可以被分为两个子集且保证每个子集中的元素不直接相连的图。
交替路:从一个未匹配点出发,依次经过未匹配边,匹配边,未匹配边......形成的路径叫做交替路。
增广路:从一个未匹配点出发,经过交替路,如果途径一个未匹配点,就把走过的路径叫做增广路。
最大匹配:在一个图的所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。
完美匹配:一个图的所有顶点都是匹配点,那么这个图就是最大匹配。
从增广路的定义上我们可以发现,每一条增广路所包含的未匹配点总比匹配点多一个。如果把增广路的所有匹配点变为未匹配点,未匹配点变为匹配点,每进行这样一次操作,未匹配点都会变少一个。我们可以每次在这个图上寻找增广路,然后进行这样的操作,直到在这个图上找不到增广路为止。而进行完这些操作后,所形成的图就是一个最大匹配的图。
下面用DFS来实现:
1 #include<cstdio> 2 #include<cstring> 3 #define N 42000 4 int next[N],to[N],num,head[N],vis[N],used[N],n,m,a,b,ans; 5 void add(int false_from,int false_to){ 6 next[++num]=head[false_from]; 7 to[num]=false_to; 8 head[false_from]=num; 9 } 10 int dfs(int x){ 11 for(int i=head[x];i;i=next[i]) 12 if(!vis[to[i]]){ 13 vis[to[i]]=1; 14 if(!used[to[i]]||dfs(used[to[i]])){ 15 used[to[i]]=x; 16 return 1; 17 } 18 } 19 return 0; 20 } 21 int main(){ 22 scanf("%d%d",&n,&m); 23 for(int i=1;i<=m;++i){ 24 scanf("%d%d",&a,&b); 25 add(a,b); 26 add(b,a); 27 } 28 for(int i=1;i<=n;++i) 29 if(!vis[i]){ 30 memset(used,0,sizeof(used)); 31 if(dfs(i)) 32 ans++; 33 } 34 printf("%d",ans); 35 return 0; 36 }