#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <map>
#include <set>
#include <queue>
#define ll long long
using namespace std;
const int N = 3050;
const int INF = 0x3f3f3f3f;
int dis; //增广路的长度
int xlink[N],ylink[N]; //xlink[i]表示左集合顶点所匹配的右集合顶点序号,ylink[i]表示右集合i顶点匹配到的左集合顶点序号
int dx[N],dy[N]; //dx,dy表示增广路中从起点到该点的距离
int head[N],tot;
int vis[3005];
void init() {
tot=0;
memset(xlink,-1,sizeof(xlink));
memset(ylink,-1,sizeof(ylink));
memset(head,-1,sizeof(head));
}
void addedge(int s,int e) {
edge[tot].v = e;
edge[tot].next = head[s];
head[s] = tot++;
}
int bfs() {
queue<int>q;
dis = INF;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=1; i<=m; i++) {
if(xlink[i]==-1) {
q.push(i);
dx[i] = 0;
}
}
while(!q.empty()) {
int u = q.front();
q.pop();
for(int e=head[u]; e!=-1; e=edge[e].next) {
int v = edge[e].v;
if(dy[v]==-1) {
dy[v] = dx[u]+1;//增广路长度+1
if(ylink[v]==-1) dis = dy[v];//找到增广路,dis表示增广路的长度
else {//点v已经与其它点相连,就将已经与v相连的点(这个点用vv表示)加入队列中,寻找是否有其它的点与vv相连
dx[ylink[v]] = dy[v]+1;
q.push(ylink[v]);
}
}
}
}
return dis!=INF;
}
int dfs(int u) {
for(int e=head[u]; e!=-1; e=edge[e].next) {
int v = edge[e].v;
if(!vis[v]&&dy[v]==dx[u]+1) {//dy[v]==dx[u] + 1表示在增广路中v是u的下一个点
vis[v] = 1;
if(ylink[v]!=-1&&dy[v]==dis) continue;
//ylink[v]!=-1 表示 x 中有与 v 相连的
//dy[v] == dis 表示 v 点是增广路中的最后一个点,
if(ylink[v]==-1||dfs(ylink[v])) {
xlink[u] = v;
ylink[v] = u;
return 1;
}
}
}
return 0;
}
int MaxMatch() {
int ans=0;
while(bfs()) {//bfs寻找一条增广路
memset(vis,0,sizeof(vis));
for(int i=1; i<=m; i++) {
if(xlink[i]==-1) {
ans+=dfs(i);
}
}
}
return ans;
}
int main() {
addedge(1,3);
addedge(1,4);
addedge(1,6);
addedge(2,1);
addedge(2,3);
addedge(2,4);
addedge(2,6);
addedge(3,3);
addedge(4,6);
addedge(4,6);
addedge(5,2);
addedge(5,5);
addedge(5,6);
int ans=MaxMatch();
printf("%d\n\n",ans);
return 0;
}
以上图为例,第一次bfs之后使用匈牙利算法形成的匹配:
由图可知左集合中点4未匹配,再一次bfs找一条增广路:
第二次使用bfs寻找增光路时dx与dy的变换情况 :
dx[4] = 0->dy[6] = 1->dx[1] = 2->dy[4] = 3(dy[3] = 3)->dx[2] = 4->dy[1] = 5;最后在右集合中找到了编号为1的未匹配点,找到了一条长度为5的增广路,再用匈牙利算法计算最大匹配.
上图就是最后找到的最大匹配.