[模板]二分图匹配


Link:题目


题目大意

我们需要做的,就是找到一种连边的方式,使得任意一个点的度最多为1,且边数最大。

给出一组数据:

input:                              output: 
3 4 5                                 3
1 1
1 2
2 1
1 4
3 3                                 

1604911-20190219080733792-1141853232.jpg此时,方案大致是这样的(当然还有其他选法)。

我们是如何找出这种匹配方式的呢?此时,就要引入匈牙利算法

匈牙利算法流程

1.首先枚举一个节点的所有边,如果当前边对应的节点不在匹配序列,则加入对应节点,返回匹配成功。

2.如果当前没有匹配成功,且对应点在之前的匹配序列(不在当前),则重新匹配对应点的对应点,执行1。

3.执行完1,2,均未匹配成功,返回失败。

下面我们来模拟一下样例数据。

首先这是原图
1604911-20190219081951192-1040424876.jpg
搜索左边第一个节点,找到一个没有匹配过的节点,加入匹配序列1。
1604911-20190219082308578-422619320.jpg
搜索第二个节点,找到一个匹配过的节点,但不在匹配序列2,重新搜索节点1...,最后返回成功。
1604911-20190219082649420-1152454670.jpg
搜索第三个节点,找到可以匹配的节点,返回成功。
1604911-20190219082807082-363577090.jpg
算法结束。
1604911-20190219083604383-923467025.jpg

代码

最后附上代码:

#include<stdio.h>
#define N 1007
struct E{
    int next,to;
}e[N*N];
int cnt=0,head[N],n,m,num,timeq=0,dfn[N],match[N],ans=0;
inline void read(int &x){
    x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();}
}
inline void add(int id,int to){//前向星存图 
    cnt++;
    e[cnt].next=head[id];
    e[cnt].to=to;
    head[id]=cnt;
}
inline bool dfs(int u){//算法核心 
    for(int i=head[u];i;i=e[i].next){//遍历 
        int v=e[i].to;
        if(dfn[v]==timeq) continue;//如果已在当前匹配序列,则直接返回 
        dfn[v]=timeq;//加入当前匹配序列 
        if(!match[v]||dfs(match[v])){//如果没有匹配过,或者重新搜索对应点返回成功 
            match[v]=u;//匹配 
            return true;//匹配成功 
        }
    }
    return false;//匹配失败 
}
int main(){
    read(n);read(m);read(num);
    for(int i=1;i<=num;i++){
        int x,y;
        read(x);read(y);
    //    if((x>n)||(y>m)) continue;
        add(x,y);//建立单向边就够了,因为不会从右边的节点开始访问 
    }
    for(int i=1;i<=n;i++){
        timeq++;//更新序列编号 
        if(dfs(i)) ans++;//搜索当前节点 
    }
    printf("%d",ans);
}

转载于:https://www.cnblogs.com/wwlwQWQ/p/10397109.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值