HDU2063---过山车(二分图匹配基础题)

【题目来源】http://acm.hdu.edu.cn/showproblem.php?pid=2063
【题意】
女生与男生配对,找出最多的配对的数目、
【思路】
按照二分图匹配里的增广路的思想,递归模拟就可以了。
增广路的大致思想是:
假设有那么一个图:
这里写图片描述
其中已经描述了对应关系,那么模拟一下匹配的过程。(全程按照代码来讲)
首先:
对A,遍历右边,找到有联系的第一个是a,那么相连,并且把linked[a]=A,也就是说与a已连接的是A
接着:
对B,遍历右边,找到有关系的第一个点a,但是a已经是A的人了,根据增广路的思想,看下,A能不能换一个人,也就是说先把vis[a]打个标记,说明该点处于待定状态,结果,A只有一个可连接的,所以,不能换,所以,对B,继续遍历右边,找到第二个可以连接的点,也就是b,连接
再然后:
对C,遍历右边,发现b是和C有关系的,那么发先linked[b]==B,也即是说b已经是B的人了,按照增广路的思想,问一下B能不能换人,然后重复刚才对B的操作,发先,并不能,于是,继续遍历右边,最终连上了c
最后:
对D,他只有唯一的对象c被C占了,那么问下C能不能换人,然后重复上面的操作,发现,并不能,所以,他没得选。。
最终结果智能匹配到三组。
这是按照代码讲解的。。。
【代码】

#include<map>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;
int k,n,m;
const int maxn=500+10;
int relax[maxn][maxn];//存下最初的相互之间的关系
int linked[maxn];//针对女生来说,已经被谁匹配到了
bool vis[maxn];//用于增广路当中往上递归(验证是否能够让位)的过程中,处于待定的点
bool find(int x)//递归
{
    for(int i=1;i<=m;i++)
    {
        if(relax[x][i]&&!vis[i])
        {
            vis[i]=1;
            if(!linked[i]||find(linked[i]))
            {
                linked[i]=x;
                vis[i]=0;//消除标记
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    while(~scanf("%d",&k))
    {
        if(k==0) break;
        scanf("%d%d",&n,&m);
        memset(relax,0,sizeof(relax));
        while(k--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            relax[x][y]=1;
        }
        memset(linked,0,sizeof(linked));
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(find(i))
                ans++;
        }
        printf("%d\n",ans);
    }
}

当然,既然是题中给出的是点与点之间的关系,那么也可以用邻接表进行存图。
【代码】

#include<map>
#include<string>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;
int k,n,m;
const int maxn=500+10;
int linked[maxn];
bool vis[maxn];
struct line
{
    int to,next;
}relax[maxn*maxn];
int first[maxn];
bool find(int x)
{
    for(int i=first[x];i!=-1;i=relax[i].next)
    {
        if(!vis[relax[i].to])
        {
            vis[relax[i].to]=1;
            if(!linked[relax[i].to]||find(linked[relax[i].to]))
            {
                linked[relax[i].to]=x;
                vis[relax[i].to]=0;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    while(~scanf("%d",&k))
    {
        if(k==0) break;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            first[i]=-1;
        int tot=0;
        while(k--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            relax[tot].to=y;
            relax[tot].next=first[x];
            first[x]=tot++;
        }
        memset(linked,0,sizeof(linked));
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(find(i))
                ans++;
        }
        printf("%d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值