二分匹配的问题很是迷人,关键点就是在怎样建图。这道题我没有想出来但是学习到了不少的东西。首先匈牙利算法的在main()里面的循环是循环的是left这边的。而find函数这是right。看来我还是没能理解怎样在增广。其次就是建图的问题,如何连边?就是将有冲突的点连接起来。这道题我用的是喜欢猫的小孩在左边,喜欢狗的在右边的方式,进行构图。其实也可以两边都是p个小孩。但是在最后找到最大匹配的时候需要/2。最后就是几个二分图不得不说的公式:1.图G的最大团=其补图的最大独立集 2.最大独立集+最小覆盖集=V
3.最小覆盖集=最大匹配;(最大团:图G的顶点的子集,设D是最大团,则D中任意两点相邻。若u,v是最大团,则u,v有边相连,其补图u,v没有边相连,所以图G的最大团=其补图的最大独立集)
上代码:
#include<cstdio>
#include<cstring>
using namespace std;
struct node{
intlnum;
inthnum;
};
int g[510][510],ans,l,r;
bool y[600];
int link[600],p;
bool find(int v){
inti;
for(i=1;i<=r-1;i++){
if(g[v][i]&&!y[i]){
y[i]=true;
if(link[i]==0|| find(link[i])){
link[i]=v;
returntrue;
}
}
}
returnfalse;
}
main(){
intn,m,i,j,num1,num2;
nodeleft[510],right[510];
charlike,hate;
while(scanf("%d%d%d",&n,&m,&p)!=-1){
l=1;r=1;
for(i=1;i<=p;i++){
getchar();
scanf("%c%d%c%d",&like,&num1,&hate,&num2);
// printf("\n");
// printf("%c%d%c%d\n",like,num1,hate,num2);
if(like=='C'){
left[l].lnum=num1;
left[l++].hnum=num2;
}
else{
right[r].lnum=num1;
right[r++].hnum=num2;
}
}
memset(g,0,sizeof(g));
for(i=1;i<=l-1;i++){
for(j=1;j<=r-1;j++){
if(left[i].lnum==right[j].hnum|| left[i].hnum==right[j].lnum)
g[i][j]=1;
}
}
ans=0;
memset(link,0,sizeof(link));
for(i=1;i<=l-1;i++){
memset(y,0,sizeof(y));
if(find(i))ans++;
}
printf("%d\n",p-ans);
}
}