题目背景
二分图
题目描述
给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数
输入输出格式
输入格式:
第一行,n,m,e
第二至e+1行,每行两个正整数u,v,表示u,v有一条连边
输出格式:
共一行,二分图最大匹配
输入输出样例
说明
n,m \leq 1000n,m≤1000, 1 \leq u \leq n1≤u≤n, 1 \leq v \leq m1≤v≤m
因为数据有坑,可能会遇到 v>mv>m 的情况。请把 v>mv>m 的数据自觉过滤掉。
算法:二分图匹配
建一个超级源点S
建一个超级汇点T
连n条S到1-n的边
连m条n+1-n+1+m到T的边
所有边的权值都是1
跑最大流
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int MAXN=*1e6;
const int INF=0x7ffff;
inline int read()
{
char c=getchar();int flag=,x=;
while(c<''||c>'') {if(c=='-') flag=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-,c=getchar();return x*flag;
}
struct node
{
int u,v,f,nxt;
}edge[MAXN];
int head[MAXN];
int num=;
inline void add_edge(int x,int y,int z)
{
edge[num].u=x;
edge[num].v=y;
edge[num].f=z;
edge[num].nxt=head[x];
head[x]=num++;
}
int n,m,e;
int S,T;
int deep[MAXN],cur[MAXN];
inline bool BFS()
{
memset(deep,,sizeof(deep));
deep[S]=;
queue<int>q;
q.push(S);
while(q.size()!=)
{
int p=q.front();q.pop();
for(int i=head[p];i!=-;i=edge[i].nxt)
if(deep[edge[i].v]==&&edge[i].f)
deep[edge[i].v]=deep[p]+,q.push(edge[i].v);
}
return deep[T];
}
int DFS(int now,int nowflow)
{
if(nowflow<=||now==T) return nowflow;
int totflow=;
for(int &i=cur[now];i!=-;i=edge[i].nxt)
{
if(deep[edge[i].v]==deep[now]+&&edge[i].f)
{
int canflow=DFS(edge[i].v,min(edge[i].f,nowflow));
totflow+=canflow;
nowflow-=canflow;
edge[i].f-=canflow;
edge[i^].f+=canflow;
if(nowflow<=) break;
}
}
return totflow;
}
int ans=;
inline void Dinic()
{
while(BFS())
{
memcpy(cur,head,sizeof(head));
ans+=DFS(S,INF);
} }
int main()
{
memset(head,-,sizeof(head));
n=read();m=read();e=read();
for(int i=;i<=e;i++)
{
int x=read(),y=read();
add_edge(x,y+n,);
add_edge(y+n,x,);
}
S=,T=INF;
for(int i=;i<=n;i++)
add_edge(S,i,),add_edge(i,S,);
for(int i=;i<=m;i++)
add_edge(i+n,T,),add_edge(T,i+n,);
Dinic();
printf("%d",ans);
return ;
}