二分图的若干结论:
最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。
最小覆盖=最大匹配
1.先把最大匹配中每条边抽取一个点,这些点至少覆盖了最大匹配中的边,因此有最大匹配<=最小覆盖(最小覆盖覆盖了所有边所以会比较大)
2.从最小覆盖中构造一个匹配(匹配数=最小覆盖数),设最小覆盖的点为v1,v2,...vn,显然对任意2点vi,vj出发总可以找到2条边e1,e2且e1,e2没有连向同一个点(想想为什么?),所以有最大匹配>=最小覆盖
由1,2得:最小覆盖=最大匹配
独立集:在所有顶点之间选一些点,两两之间无连线。这些点构成一个独立集。
对于二分图:最大独立集(点数最多的独立集)=顶点个数-最小点覆盖(最大匹配),用反证法很容易证。
最小路径覆盖与二分图:记住最小路径覆盖=顶点数-最大匹配
具体见这里
二分图匹配先贴模板:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxK = 1005;
const int maxn = 1005;
int map[maxK][maxK],cx[maxn],cy[maxn],nx,ny,K;
bool vis[maxn];
int dfs(int s){
for(int i=0; i<ny; i++){
if(!vis[i] && map[s][i]){
vis[i] = 1;
if(cy[i]==-1 || dfs(cy[i])){
cy[i] = s;
cx[s] = i;
return 1;
}
}
}
return 0;
}
int main()
{
while(scanf("%d",&nx)==1 && nx){
scanf("%d%d",&ny,&K);
int i,x,y,z;
memset(map,0,sizeof(map));
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
for(i=0; i<K; i++){
scanf("%d%d%d",&x,&y,&z);
if(y && z)
map[y][z] = 1;
}
int ans=0;
for(i=0; i<nx; i++)
if(cx[i] == -1){
memset(vis,0,sizeof(vis));
ans += dfs(i);
}
printf("%d\n",ans);
}
return 0;
}