匈牙利算法用于二分图最大匹配
一、DFS 匈牙利算法
1. 邻接矩阵实现
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAXN 2005
int n,m,ans;
int vis[MAXN];
int col[MAXN];
int match[MAXN];
int map[MAXN][MAXN];
void color(int u, int cl)
{
col[u] = cl;
for (int j=1;j<=n;j++)
{
if (map[u][j] && !col[j])
{
color(j, 3-cl);
}
}
}
bool Hungary(int u)
{
for (int i=1;i<=n;i++)
if (map[u][i] && !vis[i])
{
vis[i] = 1;
if (!match[i]|| Hungary(match[i]))
{
match[i] = u;
return 1;
}
}
return 0;
}
int main(void)
{
cin >> n >> m;
for (int i=1;i<=m;i++)
{
int x,y;
cin >> x >> y;
x++;
y++;
map[x][y] = map[y][x] = 1;
}
for (int i=1;i<=n;i++)
{
if (!col[i])
{
color(i, 1);
}
}
for (int i=1;i<=n;i++)
{
if (col[i] != 1) continue;
memset(vis, 0, sizeof(vis));
ans += Hungary(i);
}
cout << n-ans;
return 0;
}
2. 链式前向星实现
#include <stdio.h>
#include <string.h>
#include <iostream>
#define MAXN 100005
using namespace std;
bool vis[MAXN];
int head[MAXN], match[MAXN], col[MAXN];
int n, m, cnt, ans;
struct node
{
int to, next;
}map[MAXN];
void add(int u, int v)
{
map[++cnt] = (node){v, head[u]};
head[u] = cnt;
}
void color(int u, int clr)
{
col[u] = clr;
for(int k=head[u];k;k=map[k].next)
{
int v = map[k].to;
if (col[v]) continue;
color(v, 3-clr);
}
}
bool Hungary(int u)
{
for (int k=head[u];k;k=map[k].next)
{
int v = map[k].to;
if (!vis[v])
{
vis[v] = 1;
if (!match[v] || Hungary(match[v]))
{
match[v] = u;
return true;
}
}
}
return false;
}
int main()
{
cin >> n >> m;
for (int i=1;i<=m;i++)
{
int u, v;
cin >> u >> v;
u++;
v++;
add(u, v);
add(v, u);
}
for (int i=1;i<=n;i++)
{
if (col[i]) continue;
color(i, 1);
}
for (int i=1;i<=n;i++)
{
if (col[i] != 1) continue;
memset(vis, 0, sizeof(vis));
ans += Hungary(i);
}
cout << n-ans;
return 0;
}
二、BFS 匈牙利算法
这个方法好奇怪,要是实在不懂大家看看就好
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
#define MAXN 510
int ans, n, m, e;
int pre[MAXN], vis[MAXN], matchL[MAXN], matchR[MAXN];
int map[MAXN][MAXN];
queue<int >q;
void Hungary(int i)
{
q.push(i);
bool find = 0;
while (!q.empty() && !find)
{
int u = q.front();
q.pop();
for (int j=1;j<=m && !find;j++)//注意&!find
{
if (vis[j] != i && map[u][j])
{
vis[j] = i;
q.push(matchR[j]);
if (matchR[j] >= 0)
{
pre[matchR[j]] = u;
}
else
{
find = 1;
int Lpoint = u, Rpoint = j;
while (Lpoint)
{
int temp = matchL[Lpoint];
matchL[Lpoint] = Rpoint;
matchR[Rpoint] = Lpoint;
Lpoint = pre[Lpoint];
Rpoint = temp;
}
}
}
}
}
}
int main()
{
cin >> n >> m >> e;
memset(matchL,-1,sizeof(matchL));
memset(matchR,-1,sizeof(matchR));
for (int i=1;i<=e;i++)
{
int u, v;
cin >> u >> v;
map[u][v] = 1;
}
for (int i=1;i<=n;i++)
{
if (matchL[i] == -1)
{
while (!q.empty()) q.pop();
Hungary(i);
if (matchL[i] != -1)
{
ans++;
}
}
}
cout << ans;
}
BFS 版的匈牙利算法也可以用链式前向星存图,但是此题有大量重边,所以用这种办法会 T 3个点。
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
#define MAXN 510
int ans, n, m, e;
int pre[MAXN], vis[MAXN], matchL[MAXN], matchR[MAXN];
int cnt, head[MAXN];
struct node{
int to,next;
}map[MAXN];
inline void add(int u,int v){
map[++cnt] = (node){v,head[u]};
head[u] = cnt;
}
queue<int >q;
void Hungary(int i)
{
q.push(i);
bool find = 0;
while (!q.empty() && !find)
{
int u = q.front();
q.pop();
for (int k=head[u];k && !find;k=map[k].next)//注意&!find
{
int v = map[k].to;
if (vis[v] != i)
{
vis[v] = i;
q.push(matchR[v]);
if (matchR[v] >= 0)
{
pre[matchR[v]] = u;
}
else
{
find = 1;
int Lpoint = u, Rpoint = v;
while (Lpoint)
{
int temp = matchL[Lpoint];
matchL[Lpoint] = Rpoint;
matchR[Rpoint] = Lpoint;
Lpoint = pre[Lpoint];
Rpoint = temp;
}
}
}
}
}
}
int main()
{
cin >> n >> m >> e;
memset(matchL,-1,sizeof(matchL));
memset(matchR,-1,sizeof(matchR));
for (int i=1;i<=e;i++)
{
int u, v;
cin >> u >> v;
add(u, v);
}
for (int i=1;i<=n;i++)
{
if (matchL[i] == -1)
{
while (!q.empty()) q.pop();
Hungary(i);
if (matchL[i] != -1)
{
ans++;
}
}
}
cout << ans;
}