您的位置:首页 > 其它

dfs,bfs的二分匹配模板(模板题hdu1150)

2016-04-29 11:45 387 查看
如果不懂匈牙利算法,请点击:该趣味算法/article/1613615.html

模板:

//DFS版本下的二分匹配算法

http://paste.ubuntu.net/16122581/

#include<cstdio>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<math.h>
#include<queue>
#include<stdlib.h>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;

//DFS版本下的二分匹配算法

const int MAXN = 300;       //最大顶点数
bool bmap[MAXN][MAXN];      //二分图
bool bmask[MAXN];     //寻找增广路径的标志数组
int nx,ny;                  //nx为左顶点的个个数,ny为右顶点的个数
int cx[MAXN];               //cx[i]表示左集合i顶点所匹配到的右集合的顶点的序号。
int cy[MAXN];               //cy[i]表示右集合i顶点所匹配到的左集合的顶点的序号。
int k;

int findpath(int u)
{
int i;
for(i=0;i<ny;i++)   //扫描每个妹子
{
//如果【有暧昧】并且【还没有标记过】
//这里标记的意思是这次查找【曾】试图改变过该妹子的归属问题
//但是没有成功,所以就不用瞎费工夫了
if(bmap[u][i]&&!bmask[i])
{
bmask[i]=1;
if(cy[i]==-1||findpath(cy[i]))   //名花无主 或者 能腾出个位置来,这里使用递归
{
cy[i]=u;
cx[u]=i;
return 1;
}
}
}
return 0;
}

int MaxMatch()
{
int res=0;                     //有多少对
int i,j;
for(int i=0;i<nx;i++)
cx[i]=-1;
for(int i=0;i<ny;i++)
cy[i]=-1;
for(int i=0;i<nx;i++)           //为男生找配偶
{
if(cx[i]==-1)
{
for(int j=0;j<ny;j++)   //这个在每一步中清空
bmask[j]=0;
res+=findpath(i);
}
}
return res;
}

int main()
{
while(~scanf("%d",&nx)&&nx)
{
scanf("%d%d",&ny,&k);
int x;
memset(bmap,0,sizeof(bmap));
int a,b;
for(int i=0;i<k;i++)
{
scanf("%d%d%d",&x,&a,&b);
if(a>0&&b>0)
bmap[a][b]=1;
}
int ans=MaxMatch();
printf("%d\n",ans);
}
return 0;
}
/*

2 2 3
0 1 1
1 2 1
2 2 2

*/


//BFS版本下的二分匹配算法

http://paste.ubuntu.net/16122732/

#include<cstdio>
#include<string.h>
#include<iostream>
using namespace std;
typedef long long LL;

//BFS版本下的二分匹配算法

//我觉得DFS的很好理解,所以我觉得套用DFS的讲,可能有偏差;

const int MAXN = 1000;      //最大顶点数
int bmap[MAXN][MAXN];        //二分图
int cx[MAXN];             //cx[i]表示左集合i顶点所匹配到的右集合的顶点的序号。
int cy[MAXN];            //cy[i]表示右集合i顶点所匹配到的左集合的顶点的序号。
int nx,ny,k;              //nx为左顶点的个个数,ny为右顶点的个数

int bmask[MAXN];        //寻找增广路径的标志数组
int que[MAXN];          //队列保存扩展顶点
int pre[MAXN];          //记录前置顶点

int MaxMatch()
{
int res=0;
int qs,qe;
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
memset(bmask,-1,sizeof(bmask));

for(int i=0;i<nx;i++)
{
if(cx[i]==-1)           //为男的寻找配偶
{
qs=qe=0;            //队列初始化
que[qe++]=i;
pre[i]=-1;
bool flag=0;
while(qs<qe&&!flag)
{
int u=que[qs];
for(int v=0;v<ny&&!flag;v++)
{
if(bmap[u][v]&&bmask[v]!=i) //如果有关系,但是这个关系并不是给我们要配对的男生
{
bmask[v]=i;             //但是...该男子强行拿过来作为妻子
que[qe++]=cy[v];        //所以女生本来的丈夫就很伤了
if(cy[v]>=0)            //如果那个人有丈夫的话,就用pre记录前置节点
{
pre[cy[v]]=u;
}
else                    //但是该女子没有丈夫,那就是刚刚好
{
flag=1;             //OK解决问题
int d=u,e=v;
while(d!=-1)        //然后这就是类似于DFS算法中的回溯,这建立了改男子配对下的状态是什么样子的。
{
int t=cx[d];
cx[d]=e;cy[e]=d;
d=pre[d];e=t;
}
}
}
}
qs++;
}
if(cx[i]!=-1)       //有多少配对的男子,就加几个
{
res++;
}
}
}
return res;
}

int main()
{
while(~scanf("%d",&nx)&&nx)
{
scanf("%d%d",&ny,&k);
int x;
memset(bmap,0,sizeof(bmap));
int a,b;
for(int i=0;i<k;i++)
{
scanf("%d%d%d",&x,&a,&b);
if(a>0&&b>0)
bmap[a][b]=1;
}
int ans=MaxMatch();
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: