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

如果不懂匈牙利算法,请点击:该趣味算法http://blog.csdn.net/dark_scope/article/details/8880547

模板:
//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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值