最大流求二分图最大匹配
本题要点:
1、二分图模型,转换为最大流模型
增加一个源点s和汇点t, 源点s和n个左部节点连线,边的容量是1,
m个右部节点和汇点t连线, 边的容量是1。
然后求该网络图从s到t的最大流,就是原图的二分图最大匹配
2、这里要求输出这 k 对的最大匹配。
用数组 ans存放,ans[i] 表示点i的下一个节点是哪个节点。
在update函数里,更新 ans 数组即可。
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
const int MaxN = 210, MaxM = 11000;
const int inf = 1 << 29;
int head[MaxN], ver[MaxM], edge[MaxM], Next[MaxM], vis[MaxN];
int incf[MaxN], pre[MaxN], ans[MaxN];
int m, n, s, t, tot, maxflow;
void add(int x, int y, int z)
{
ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
ver[++tot] = x, edge[tot] = 0, Next[tot] = head[y], head[y] = tot;
}
bool bfs()
{
memset(vis, 0, sizeof vis);
queue<int> q;
q.push(s);
vis[s] = 1;
incf[s] = inf;
while(q.size())
{
int x = q.front(); q.pop();
for(int i = head[x]; i; i = Next[i])
{
if(edge[i])
{
int y = ver[i];
if(vis[y]) continue;
incf[y] = min(incf[x], edge[i]);
pre[y] = i; //记录前驱
q.push(y), vis[y] = 1;
if(y == t)
return true;
}
}
}
return false;
}
void update()
{
int x = t;
while(x != s)
{
int i = pre[x];
ans[ver[i ^ 1]] = x;
edge[i] -= incf[t];
edge[i ^ 1] += incf[t];
x = ver[i ^ 1];
}
maxflow += incf[t];
}
int main()
{
scanf("%d%d", &m, &n);
tot = 1, s = 0, t = n + 1;;
for(int i = 1; i <= m; ++i) //起点 s 连上 m个左部节点
{
add(0, i, 1);
}
for(int i = m + 1; i <= n; ++i) // n - m 个右部节点连上 汇点t
{
add(i, n + 1, 1);
}
int x, y;
while(scanf("%d%d", &x, &y) != EOF)
{
if(-1 == x && -1 == y)
break;
add(x, y, 1);
}
while(bfs())
{
update();
}
printf("%d\n", maxflow);
for(int i = 1; i <= m; ++i)
{
// printf("ans[%d] = %d\n", i, ans[i]);
if(ans[i])
{
printf("%d %d\n", i, ans[i]);
}
}
return 0;
}
/*
5 10
1 7
1 8
2 6
2 9
2 10
3 7
3 8
4 7
4 8
5 10
-1 -1
*/
/*
4
1 7
2 9
3 8
5 10
*/