洛谷P3386【模板】二分图匹配

题目背景

二分图

题目描述

给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数

输入输出格式

输入格式:

第一行,n,m,e
第二至e+1行,每行两个正整数u,v,表示u,v有一条连边

输出格式:

共一行,二分图最大匹配

输入输出样例

输入样例#1:
1 1 1
1 1
输出样例#1:
1

说明

n,m≤1000,1≤u≤n, 1≤v≤m
因为数据有坑,可能会遇到 v>mv>m 的情况。请把 v>mv>m 的数据自觉过滤掉。

算法:二分图匹配

【题解】

二分图匹配用匈牙利算法或者网络流都可做(ps:能用匈牙利算法做的都能用网络流做),但是效率差别较大。

网络流可达30ms,邻接表匈牙利1440ms,邻接矩阵匈牙利4036ms。

而我只是一个提高组的蒟蒻,没兴趣搞省选级别的网络流。。。就来个邻接表匈牙利算法吧。

(吐槽:为什么大佬的邻接表都有STL和指针,看得好难受。。。)

注意事项:

1、存点的结构体的空间尽量大,我的程序开到了n×n×5。(开n时10个点RE。。。)

2、要去掉u>n和v>m的情况。(但邻接矩阵没必要)

3、程序注释非常重要,有助于理解匈牙利算法精髓,希望大家仔细阅读。

4、邻接表既省时间又省空间,建议多用。

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define fp(i,a,b) for(int i=a;i<=b;i++)
#define fq(i,a,b) for(int i=a;i>=b;i--)
#define il inline
#define re register
#define ll long long 
using namespace std;
bool vis[4005]={};
int n,m,k,ans=0,link[4005]={},head[4005]={},cnt=0;//vis用来标记   link记录情侣关系  
struct Edge
{
    int to,next;
}e[4000005];//e记录有好感
il int gi()
{
   int x=0;
   short int t=1;
   char ch=getchar();
  while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  if(ch=='-') t=-1,ch=getchar();
  while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  return x*t;
}
il bool dfs(int u)//匈牙利算法
{
    for(int i=head[u];i;i=e[i].next)//扫描每个妹子,这里已保证有好感
    {
        int v=e[i].to;
        if(!vis[v])//if (单身)
        {
            vis[v]=1;  
            if(!link[v]||dfs(link[v])) {link[v]=u;return 1;}//名花无主||者能腾出个位置来,这里使用递归
        }
    }
    return 0;
}
int main()
{
    n=gi();m=gi();k=gi();
    fp(i,1,k)
    {
        int u=gi(),v=gi();
        if(u>n||v>m) continue;//去掉无效情况
        e[++cnt]=(Edge){v,head[u]};head[u]=cnt;//有好感就连条边(标准链式前向星存储)
    }
    fp(i,1,n)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i)) ans++;//情侣配成
    }
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值