最大二分匹配基础题,看思路蛮简单的,结果那递归错误百出,改得累死。
没接触过的题目类型,只靠思路写代码写起来很慢,很致命的一点,以后要多提高用代码表达思路的能力,还有,细心,要细心!!
6 3 3 1 1 1 2 1 3 2 1 2 3 3 1 0
3//--------------------------------------------------没骗人吧,果然是最基础的最大二分匹配吧。
记下做题过程吧。
先说思路:遍历女点,每次找一个增广路,然后增广。
增广路是什么呢?比如这样一条,女-男x女-男x女-男,'-'表示可以连但还没连,'x'表示可以连且已经连,而且最后个男的没跟别的女的连。
那这样一条可以转变成女x男-女x男-女x男。配对比原来多了一个吧。
女方每个点找一次就够了,因为找了后如果被配对了,就算被增广还是配对着的,这个好理解;如果没被配对……我没用,我说不清楚,我低能 ……假设有个女的本来无法配对,但在其他女的配对之后,她变得可以配对了,那她现在这条路上必有某一点本来就存在于另一条增广路上,只有这样,才会在别的路增广时改变了这点从而导致这个女点变得可以增广。但既然有一点本来就存在于一条增广路上,众所周知,一条增广路被一点分开后两边的情况是相反的OXO XOXO,总存在一边,接到那被改变的点上去之后,使那女点可以增广。也就是说在其他点增广之前就可以增广了,与假设不符,所以不能增广的还是不能增广,再回头来看也没用。
具体实现呢,增广路用深搜找,基于找的点是男或女要略分开考虑,如果搜到的点已在当前路上了就跳过,最后找到个没被连过的男点之后停止,返回1,回溯,路上每个边反转。找不到么返回0,不改变。遍历女点时,若找到增广路,计数器++,因为每个增广路只增加一个配对,最后返回计数器的值就是最大二分匹配了。
#include<iostream>
int K,N[2];
int map[501][501],link[501][501];
bool mark[501],tmark[2][501];
void get_map(){
int a,b;
memset(map,0,sizeof(map));
while(K--){
scanf("%d%d",&a,&b);
map[a][b]=1;
}
}
bool broader(int x,int y){
// printf("id=%d,sex=%d/n",x,y);
if(y==0&&!mark[x]){
mark[x]=1;
return 1;
}
// printf("get/n");
int i;
for(i=1;i<=N[y];i++){
if(tmark[y][i])continue;
tmark[y][i]=1;
if(y==0&&!map[i][x]||y==1&&!map[x][i]||y==0&&link[i][x]==0||y==1&&link[x][i]==1||!broader(i,1-y)){
tmark[y][i]=0;
continue;
}
tmark[y][i]=0;//printf("^");
if(y==0)link[i][x]=0;
else link[x][i]=1;
return 1;
}
return 0;
}
void go(){
int i,j,count=0;
memset(mark,0,sizeof(mark));
memset(link,0,sizeof(link));
memset(tmark,0,sizeof(tmark));
for(i=1;i<=N[0];i++){
tmark[0][i]=1;
//printf("i=%d/n",i);
for(j=1;j<=N[1];j++){
tmark[1][j]=1;
if(!map[i][j]||link[i][j]||!broader(j,0)){tmark[1][j]=0;continue;}
tmark[1][j]=0;
count++;
link[i][j]=1;
break;
}
tmark[0][i]=0;
}
printf("%d/n",count);
}
int main(){
while(scanf("%d",&K)&&K){
scanf("%d%d",&N[0],&N[1]);
get_map();
go();
}
return 0;
}
~~~~~~~~~~~~~~~~~~~~以下简化版~~~~~~~~~~~~~~~~~~~~~~~
哇,粉红色好可爱好喜欢哦~~~~~
#include<iostream>
int K,F,M;
bool map[501][501];
int mark[501];
bool tmark[501];
void get_map(){
int a,b;
memset(map,0,sizeof(map));
while(K--){
scanf("%d%d",&a,&b);
map[a][b]=1;
}
}
bool broader(int x){
int i;
for(i=1;i<=M;i++){
if(!map[x][i]||tmark[i])continue;
tmark[i]=1;
if(!mark[i]||broader(mark[i])){
mark[i]=x;
return 1;
}
}
return 0;
}
void go(){
int i,count=0;
memset(mark,0,sizeof(mark));
for(i=1;i<=F;i++){
memset(tmark,0,sizeof(tmark));
if(broader(i))count++;
}
printf("%d/n",count);
}
int main(){
while(scanf("%d",&K)&&K){
scanf("%d%d",&F,&M);
get_map();
go();
}
return 0;
}