Hopcroft-Karp算法
详细算法讲解博客,推荐:https://blog.csdn.net/wall_f/article/details/8248373
基本算法
该算法主要是对匈牙利算法的优化,在寻找增广路径的时候同时寻找多条不相交的增广路径,形成极大增广路径集,然后对极大增广路径集进行推广。在寻找增广路径集的每个阶段,找到的增广路径集都具有相同的长度,且随着算法的进行,增广路径的长度不断地扩大。可以证明,最多增广 n0.5 次就可以得到最大匹配。
const int MAXN=510;// 最大点数
const int INF=1<<28;// 距离初始值
int bmap[MAXN][MAXN];//二分图
int cx[MAXN];//cx[i]表示左集合i顶点所匹配的右集合的顶点序号
int cy[MAXN]; //cy[i]表示右集合i顶点所匹配的左集合的顶点序号
int nx,ny;
int dx[MAXN];
int dy[MAXN];
int dis;
bool bmask[MAXN];
//寻找 增广路径集
bool searchpath(){
queue<int>Q;
dis=INF;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=1;i<=nx;i++){
//cx[i]表示左集合i顶点所匹配的右集合的顶点序号
if(cx[i]==-1){
//将未遍历的节点 入队 并初始化次节点距离为0
Q.push(i);
dx[i]=0;
}
}
//广度搜索增广路径
while(!Q.empty()){
int u=Q.front();
Q.pop();
if(dx[u]>dis) break;
//取右侧节点
for(int v=1;v<=ny;v++){
//右侧节点的增广路径的距离
if(bmap[u][v]&&dy[v]==-1){
dy[v]=dx[u]+1; //v对应的距离 为u对应距离加1
if(cy[v]==-1) dis=dy[v];
else{
dx[cy[v]]=dy[v]+1;
Q.push(cy[v]);
}
}
}
}
return dis!=INF;
}
//寻找路径 深度搜索
int findpath(int u){
for(int v=1;v<=ny;v++){
//如果该点没有被遍历过 并且距离为上一节点+1
if(!bmask[v]&&bmap[u][v]&&dy[v]==dx[u]+1){
//对该点染色
bmask[v]=1;
if(cy[v]!=-1&&dy[v]==dis){
continue;
}
if(cy[v]==-1||findpath(cy[v])){
cy[v]=u;cx[u]=v;
return 1;
}
}
}
return 0;
}
//得到最大匹配的数目
int MaxMatch(){
int res=0;
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
while(searchpath()){
memset(bmask,0,sizeof(bmask));
for(int i=1;i<=nx;i++){
if(cx[i]==-1){
res+=findpath(i);
}
}
}
return res;
}
【例题:HDU 2063 过山车】
http://acm.hdu.edu.cn/showproblem.php?pid=2063
Problem Description
RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了。可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做partner和她同坐。但是,每个女孩都有各自的想法,举个例子把,Rabbit只愿意和XHD或PQK做partner,Grass只愿意和linle或LL做partner,PrincessSnow愿意和水域浪子或伪酷儿做partner。考虑到经费问题,boss刘决定只让找到partner的人去坐过山车,其他的人,嘿嘿,就站在下面看着吧。聪明的Acmer,你可以帮忙算算最多有多少对组合可以坐上过山车吗?
Input
输入数据的第一行是三个整数K , M , N,分别表示可能的组合数目,女生的人数,男生的人数。0<K<=1000
1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。
Output
对于每组数据,输出一个整数,表示可以坐上过山车的最多组合数。
Sample Input
6 3 3
1 1
1 2
1 3
2 1
2 3
3 1
0
Sample Output
3
可以直接匈牙利算法,这里只是看一下自己的板子对不对
//Hopcroft-Karp算法模板
const int maxn = 510;
const int inf = 0x3f3f3f3f3f;
int G[maxn][maxn];
int cx[maxn],cy[maxn];
int nx,ny;
int dx[maxn],dy[maxn];
int dis;
bool vis[maxn];
bool searchpath(){
queue<int>q;
dis=inf;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=1;i<=nx;i++){
if(cx[i]==-1){
q.push(i);
dx[i]=0;
}
}
while(!q.empty()){
int u = q.front();
q.pop();
if(dx[u]>dis) break;
for(int v=1;v<=ny;v++){
if(G[u][v]&&dy[v]==-1){
dy[v] = dx[u] + 1;
if(cy[v]==-1) dis = dy[v];
else{
dx[cy[v]] = dy[v] + 1;
q.push(cy[v]);
}
}
}
}
return dis!=inf;
}
int findpath(int u){
for(int v=1;v<=ny;v++){
if(!vis[v]&&G[u][v]&&dy[v]==dx[u]+1){
vis[v] = 1;
if(cy[v]!=-1&&dy[v]==dis){
continue;
}
if(cy[v]==-1||findpath(cy[v])){
cy[v] = u;
cx[u] = v;
return 1;
}
}
}
return 0;
}
int MaxMatch(){
int res=0;
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
while(searchpath()){
memset(vis,0,sizeof(vis));
for(int i=1;i<=nx;i++){
if(cx[i]==-1){
res += findpath(i);
}
}
}
return res;
}
AC代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<ctime>
#include<map>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int maxn = 510;
const int inf = 0x3f3f3f3f3f;
int G[maxn][maxn];
int cx[maxn],cy[maxn];
int nx,ny;
int dx[maxn],dy[maxn];
int dis;
bool vis[maxn];
bool searchpath(){
queue<int>q;
dis=inf;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=1;i<=nx;i++){
if(cx[i]==-1){
q.push(i);
dx[i]=0;
}
}
while(!q.empty()){
int u = q.front();
q.pop();
if(dx[u]>dis) break;
for(int v=1;v<=ny;v++){
if(G[u][v]&&dy[v]==-1){
dy[v] = dx[u] + 1;
if(cy[v]==-1) dis = dy[v];
else{
dx[cy[v]] = dy[v] + 1;
q.push(cy[v]);
}
}
}
}
return dis!=inf;
}
int findpath(int u){
for(int v=1;v<=ny;v++){
if(!vis[v]&&G[u][v]&&dy[v]==dx[u]+1){
vis[v] = 1;
if(cy[v]!=-1&&dy[v]==dis){
continue;
}
if(cy[v]==-1||findpath(cy[v])){
cy[v] = u;
cx[u] = v;
return 1;
}
}
}
return 0;
}
int MaxMatch(){
int res=0;
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
while(searchpath()){
memset(vis,0,sizeof(vis));
for(int i=1;i<=nx;i++){
if(cx[i]==-1){
res += findpath(i);
}
}
}
return res;
}
int main(void){
int num;
while(scanf("%d",&num)&&num){
memset(G,0,sizeof(G));
scanf("%d%d",&nx,&ny);
int u,v;
for(int j=1;j<=num;j++){
scanf("%d%d",&u,&v);
G[u][v]=1;
}
printf("%d\n",MaxMatch());
}
return 0;
}