二分匹配的問題很是迷人,關鍵點就是在怎樣建圖。這道題我沒有想出來但是學習到了不少的東西。首先匈牙利算法的在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);
}
}