算法过程:
假设两部分节点集合称为P,Q集合。
match[i]代表Q集合中的i号节点所对应的P集合中的配对点.
vis[i] 代表Q集合中哪些点在本次增广中已经被访问.
1.遍历P集合所有节点.
2.对于每个节点i,清空vis数组,再dfs求一条 关于i的增广路.
dfs求增广路:
1.对于当前节点,遍历其所有邻接点 i
1.1对于每个邻接点,如果已经被访问过了,continue;否则 vis数组置1
1.2如果i点尚未配对 或者 dfs可求出一条关于i的增广路.将其配对并返回真 否则继续找下一个邻接点.
2 如果每一个都没有,则返回假.
解释:
①复杂度:O(NM) --- N为节点数,E为边数.
②关键核心:给当前节点腾位置.
洛谷模板题AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,e;
const int maxn = 1e3+5;
const int maxe = 1e6+5;
int u[maxe],v[maxe],first[maxn],nextt[maxe],sign;
//二分图匹配
int match[maxn],vis[maxn];
int ans;
void addedge(int x,int y)
{
u[++sign] = x;
v[sign] = y;
nextt[sign] = first[x];
first[x] = sign;
}
int dfs(int x)
{
for(int i = first[x];i;i = nextt[i])
{
if(vis[v[i]])
continue;
vis[v[i]] = 1;
if(!match[v[i]] || dfs(match[v[i]]))
{
match[v[i]] = x;
return 1;
}
}
return 0;
}
int main()
{
scanf("%d%d%d",&n,&m,&e);
int cnt = 0;
for(int i = 1;i<=e;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(x > n || y> m)
continue;
cnt++;
addedge(x,y);
}
for(int i = 1;i<=n;i++)
{
memset(vis,0,sizeof vis);
ans += dfs(i);
}
printf("%d\n",ans);
return 0;
}
//
/*
5 5 5
1 1
1 2
2 2
2 3
3 1
*/